| Abbreviation | Explanation |
|---|---|
| ACF | Active case finding; the process of actively identifying people with TB. ACF aims to identify people with TB either in those who do not recognize that they have symptoms, or those who do recognize symptoms but for whatever reason do not, or cannot, access services at health-care facilities. |
| CAD | Computer aided diagnostic |
| CRP | C reactive protein; a blood inflammatory marker measured using point of care devices or laboratory assays, which is elevated in the presence of infections, inflammatory or neoplastic (cancer) conditions, including TB. WHO recommends CRP as a screening tool for TB among people living with HIV and research studies indicate CRP could also have a use in TB screening among people not infected with HIV. |
| CXR | Chest x-ray |
| DYT | Diagnostic yield per test |
| GA | Gastric aspirate |
| ICF | Intensified case finding at health facilities; an activity, recommended by the WHO, intended to detect possible TB cases among people attending health facilities for reasons not associated with TB (e.g. general clinics or maternity wards). |
| IDP | Internally displaced people |
| LAM | Lipoarabinomannan |
| MCMC | Markov Chain Monte Carlo |
| NPA | Nasopharyngeal aspiration |
| NPV | Negative predictive value |
| PCF | Passive case finding |
| PLWH | People / person living with HIV |
| POC | Point-of-care |
| PPV | Positive predictive value |
| RDT | Rapid diagnostic test |
| SAP | Statistical analysis plan |
| SSM | Sputum smear microscopy |
| TB | tuberculosis |
Start 4 All Phase 1 - Statistical Analysis Plan
v1.3 (International)
1 List of abbreviations
Table 1 lists all abbreviations used throughout this document.
2 Protocol version
This Statistical Analysis Plan (SAP) v1.3 is based on the Start 4 All International Protocol v1.6, dated 22 May 2023.
2.1 Version history
| Version | Date | Author | Edits |
|---|---|---|---|
| 1.3 | 2025-05-27 | Marc Henrion | All analyses tested; mock-up output for PCF/ICF setting included |
| 1.2 | 2024-05-27 | Marc Henrion | Clarified agorithms with pooled Xpert Ultra testing and updated JAGS files correspondingly |
| 1.1 | 2025-05-26 | Marc Henrion | Descriptive analysis mock-ups added; full JAGS model files added; details of MCMC run parameters; added JAGS version number; slightly revised secondary analyses |
| 1.0 | 2025-05-25 | Marc Henrion | First full version of the SAP (while development versions 0.1 to 0.14 exist, no version history record was kept prior to v1.0) |
3 Protocol summary
Start 4 All is a large, UNITAID funded 4-year tuberculosis (TB) study programme, running in 7 countries and consisting of 2 phases:
Phase 1 (18 months) - cross-sectional surveys to generate data on diagnostic assay performances in different countries and different populations and identifying optimal diagnostic test combinations (for screening purposes).
Phase 2 (30 months) - a large, multi-country implementation study to evaluate the chosen optiomal combinations in the different settings.
This SAP focuses on Phase 1, with a separate SAP being written for the trial in Phase 2. There will also be a separate analysis plan for the economic evaluation of the diagnostic test combinations.
3.1 Study design
Phase 1 consists of multiple cross-sectional surveys in 7 countries and in different general and marginalised populations within those countries.
| Population | Currently implemented TB screening / diagnosis approach | Local laboratory | Country | X-ray availability | Case finding approach | % with TB among those testes | Additional diagnostic tests and test combinations evaluated as part of Start 4 All |
|---|---|---|---|---|---|---|---|
| Primary health care attenders | Sympton screen; sputum smear microscopy; sputum transport for Xpert | None / basic | Bangladesh, Brazil, Cameroon, Kenya, Malawi, Nigeria, Viet Nam | No | PCF / ICF | 5-15% | CAD CXR, POC CRP, CRP RDT, LAM, pooling Ultra |
| District / secondary hospital attenders | Symptom screen; sputum Xper testing (where available); 1st gen LAM for HIV positive admissions (where avilable) | Medium / some with Xpert | Bangladesh, Cameroon, Kenya, Malawi, Nigeria, Viet Nam | Yes | PCF / ICF | 10-20% | CAD CXR, POC CRP, CRP RDT, LAM, pooling Ultra |
| Key / marginalised populations (informal settlements, IPDs, refugees, rural poor, pastoralists) | Symptom screen; mobile chest X-ray (predominantly human interpretation); sputum transport for smear/Xpert/culture | None | Bangladesh, Cameroon, Nigeria | Limited / mobile trucks | PCF / ICF / ACF | 0.5-10% | CAD CXR, POC CRP, CRP RDT, LAM, Pooling Ultra |
| Children | Symptom screen; Xpert testing (stool, NPA, GA, where available); X-ray (human interpretation); IGRA (Viet Nam) | Medium / some with Xpert | Cameroon, Viet Nam | Yes (if in hospital) | PCF / ICF / ACF | 8-12% | CAD CXR, POC CRP, CRP RDT, LAM, pooling Ultra |
Table 3 summarises the different surveys. This study design was selected because (together with diagnostic clinical trials) surveys are considered the best design for the evaluation of diagnostics. We will evaluate the performance of HIV testing, CRP, computer assisted digital X-Rays (CAD CXR), testing multiple sputum samples by pooling them together and testing the pool with a single Xpert Ultra cartridge and urine lipoarabinomannan (LAM) as screening tests for TB. Although the performance of these tests has been described among individuals with presumptive TB, there are now updated prototypes (e.g. LAM) or software (e.g. CAD CXR) for some platforms, there is limited information on their performance among key populations (e.g. nomads/internally displaced people) and hardly any information on their performance in primary health care settings.
A composite microbiological reference standard will be used to describe the sensitivity, specificity and positive and negative predictive value of different assays and their combinations. The composite standard will classify participants as ‘microbiologically confirmed’, if their sputum culture or Xpert Ultra (as a single test) are positive or as ‘unlikely TB’ if they have negative culture AND negative Xpert Ultra results.
Table 4 summarises the screening assays evaluated in this study.
| Assay type | Assay |
|---|---|
| HIV testing | HIV |
| Point-of-care C-Reactive Protein (quantitative) | POC CRP |
| Point-of-care C-Reactive Protein (semi-quantitative) | CRP RDT |
| Computer-aided detection from digital chest X-ray | Digital chest X-ray + Qure.ai |
| Urine Lateral Flow Test | FujiLAM |
| Molecular diagnostic | Xpert Ultra |
| Molecular diagnostic | Pooled Xpert Ultra |
3.2 Study Endpoints
3.2.1 Primary endpoint
Generation of robust estimates of the diagnostic accuracy and performance of TB diagnostic tests and test combinations in primary healthcare settings and key and vulnerable populations.
3.2.2 Secondary study endpoints
Estimates of the predicted performance of TB diagnostic test combinations and how they perform in specific populations.
Selection of the optimal TB diagnostic test combinations for implementation and scale-up in primary healthcare settings and key and vulnerable populations in terms of their cost-efficiency, feasibility, and modelled accuracy.
3.3 Sample size
Diagnostic test combinations for the Phase 1 cross-sectional studies are tailored by country and key populations. We envisage conducting one cross sectional study among pastoralists, one study among refugees and IDPs, one among people living in informal settlements, one among the rural poor, and 6 studies among populations in clinical facilities (total of 18 cross sectional studies across 6 countries). Each study will comprise about 600 participants, including a minimum of 100 bacteriologically confirmed participants in most populations. The key populations and number of studies for Phase 1 studies are shown below.
The sample sizes were chosen to comply with the sample size criterion required for WHO guideline development and to achieve an acceptable level of precision for the estimates of the performance of the diagnostic tests. The sample sizes are also suitable for estimating costs and cost-efficiency of the TB diagnostic combinations.
tbl-sampSizeCalc gives the number of TB cases / number of subjects at different prevalence values for TB and different values of precision for 95% CI of point estimate of number of bacteriologically confirmed TB cases identified from each sample population. Populations with low proportions (<10%) of bacteriologically confirmed TB (children, ACF in Viet Nam), will use the same cross-sectional design, but the number of bacteriologically confirmed participants will be purposely enriched by inviting participants attending adjacent centers to the study centers. Once included in the study, participants will undergo all tests in the diagnostic combination.
The calculations in tbl-sampSizeCalc have been obtained using the standard Wald normal approximation:
\[ n_{unadj}=p\cdot(1-p)\cdot\left(\frac{z_{\alpha/2}}{E}\right)^2 \] where \(p\) = target proportion (sensitivity in your case; \(p=0.9\)), E = target precision (or margin-of-error) and \(z_{\alpha/2}\) is the (two-sided) critical value from the normal distribution for significance level \(\alpha\) (in our case \(\alpha=0.05\) and \(z_{alpha/2}=1.96\)).
Code
sampSize_OnePropCI<-function(p_hat,E=NULL,n=NULL,alpha=0.05,method="WaldNormalApprox"){
# p_hat = expected proportion
# E = desired error of margin (half width of the confidence interval); if specified then n gets computed
# n = fixed sample size; if specified then E gets computed
# alpha = 1 - confidence level
# method = one of "WaldNormalApprox" or "WilsonScoreApprox"
# NOTE: exactly one of n, E needs to be specified -- they cannot both be set to NULL or both be specified
z<-qnorm(1-alpha/2)
if(is.null(n) & !is.null(E)){
if(method=="WaldNormalApprox"){
n<-p_hat*(1-p_hat)*(z/E)^2
}else if(method=="WilsonScoreApprox"){
a<-1
b<-(2-p_hat*(1-p_hat)/E^2)*z^2
c<-(4*E^2-1)*(z^4)/(4*E^2)
n<-(-b + sqrt(b^2-4*a*c))/(2*a)
}else{stop("The method parameter needs to be one of WaldNormalApprox or WilsonScoreApprox")}
return(n)
}else if (is.null(E) & !is.null(n)){
if(method=="WilsonScoreApprox"){warning("Argument method is set to WilsonScoreApprox but this will be ignored and WaldNormalApprox be used instead.")}
E<-sqrt((p_hat*(1-p_hat)*z^2)/n)
return(E)
}else{
stop("E and n cannot both be NULL or both be specified - you need to specify one of these two and leave the other unspecified / NULL.")
}
}
dfSS<-data.frame(
tbPrevalence=c(1:5,8:10,12,15,20,27)/100,
prec5=NA,
prec6=NA,
prec7=NA,
prec8=NA,
prec10=NA,
prec15=NA
) %>%
mutate(
prec5=paste(sep=" / ",ceiling(sampSize_OnePropCI(p_hat=0.9,E=0.05)),ceiling(c(ceiling(sampSize_OnePropCI(p_hat=0.9,E=0.05))/tbPrevalence))),
prec6=paste(sep=" / ",ceiling(sampSize_OnePropCI(p_hat=0.9,E=0.06)),ceiling(c(ceiling(sampSize_OnePropCI(p_hat=0.9,E=0.06))/tbPrevalence))),
prec7=paste(sep=" / ",ceiling(sampSize_OnePropCI(p_hat=0.9,E=0.07)),ceiling(c(ceiling(sampSize_OnePropCI(p_hat=0.9,E=0.07))/tbPrevalence))),
prec8=paste(sep=" / ",ceiling(sampSize_OnePropCI(p_hat=0.9,E=0.08)),ceiling(c(ceiling(sampSize_OnePropCI(p_hat=0.9,E=0.08))/tbPrevalence))),
prec10=paste(sep=" / ",ceiling(sampSize_OnePropCI(p_hat=0.9,E=0.1)),ceiling(c(ceiling(sampSize_OnePropCI(p_hat=0.9,E=0.1))/tbPrevalence))),
prec15=paste(sep=" / ",ceiling(sampSize_OnePropCI(p_hat=0.9,E=0.15)),ceiling(c(ceiling(sampSize_OnePropCI(p_hat=0.9,E=0.15))/tbPrevalence)))
) %>%
mutate(tbPrevalence=paste(sep="",100*tbPrevalence,"%"))
dfSS %>%
kable(row.names=FALSE,col.names=c("","5%","6%","7%","8%","10%","15%")) %>%
kable_styling(full_width=FALSE) %>%
add_header_above(c("TB prevalence"=1,"Precision"=6)) %>%
add_header_above(c(" "=1,"Expected number microbiologically confirmed / number required in sample"=6))| 5% | 6% | 7% | 8% | 10% | 15% | |
|---|---|---|---|---|---|---|
| 1% | 139 / 13900 | 97 / 9700 | 71 / 7100 | 55 / 5500 | 35 / 3500 | 16 / 1600 |
| 2% | 139 / 6950 | 97 / 4850 | 71 / 3550 | 55 / 2750 | 35 / 1750 | 16 / 800 |
| 3% | 139 / 4634 | 97 / 3234 | 71 / 2367 | 55 / 1834 | 35 / 1167 | 16 / 534 |
| 4% | 139 / 3475 | 97 / 2425 | 71 / 1775 | 55 / 1375 | 35 / 875 | 16 / 400 |
| 5% | 139 / 2780 | 97 / 1940 | 71 / 1420 | 55 / 1100 | 35 / 700 | 16 / 320 |
| 8% | 139 / 1738 | 97 / 1213 | 71 / 888 | 55 / 688 | 35 / 438 | 16 / 200 |
| 9% | 139 / 1545 | 97 / 1078 | 71 / 789 | 55 / 612 | 35 / 389 | 16 / 178 |
| 10% | 139 / 1390 | 97 / 970 | 71 / 710 | 55 / 550 | 35 / 350 | 16 / 160 |
| 12% | 139 / 1159 | 97 / 809 | 71 / 592 | 55 / 459 | 35 / 292 | 16 / 134 |
| 15% | 139 / 927 | 97 / 647 | 71 / 474 | 55 / 367 | 35 / 234 | 16 / 107 |
| 20% | 139 / 695 | 97 / 485 | 71 / 355 | 55 / 275 | 35 / 175 | 16 / 80 |
| 27% | 139 / 515 | 97 / 360 | 71 / 263 | 55 / 204 | 35 / 130 | 16 / 60 |
The resulting number \(n_{unadj}\) needs to be adjusted for the TB prevalence, \(p_{TB}\):
\[ n_{adj}=\frac{n_{unadj}}{p_{TB}} \]
We further need to take into account different levels of expected attrition (due to loss-to-follow-up; unusable data or other causes):
\[ n_{final}=\frac{n_{adj}}{1-p_{attr}} \]
where \(p_{attr}\) is the expected proportion of attrition.
The studies will be analyzed individually by countries, and then as a single multi-country evaluation. The latter aims to achieve the requirements of data for WHO guidance, which requests at least 250 individuals with bacteriologically confirmed TB.
As shown in Table 6, the total sample size to be enrolled varies with the average TB prevalence, target precision and expected loss-to-follow-up (individuals not completing a diagnostic process) in the individual countries and sites. However, with the assumptions shown in Table 6, and assuming an overall proportion of 50% people living with HIV (PLWH) adult participants, we estimate a sample size of 7,200 PLWH and 7,200 HIV-negative persons will include at least 548 PLWH and 548 HIV-negative persons (total 1,096) with a microbiologically confirmed diagnosis of TB.
It is expected that countries with a high burden of HIV-associated TB (Brazil, Cameroon, Kenya, Malawi, Nigeria) will recruit an even higher ratio of PLWH to HIV-negative participants. If the recruitment of PLWH is lower than expected, countries with high burden of HIV-associated TB will enrich recruitment towards this population by recruiting in HIV care and treatment clinics and outpatient centres.
The number of adult males is expected to be higher than the number of females, as more males are affected by TB and a higher proportion of males than females attend primary and secondary clinics. The proportion of participants with TB that is obtained at the end of Phase 1 may vary from the expected proportion of participants with TB due to the inclusion of ICF and ACF in the study in settings in which they are not normally applied (i.e. ICF being conducted in PHC clinics). Additionally, some populations maybe feel more encouraged or discouraged to participate in the study, which may be reflected in the proportion of TB cases for a particular setting and the reasons behind this may be elucidated during the Realist Evaluation.
Code
dfSSCountry<-data.frame(
country=c(rep("Cameroon",4),rep("Nigeria",4),rep("Kenya",2),rep("Bangladesh",3),rep("Brazil",2),rep("Viet Nam",3),rep("Malawi",1),"TOTAL"),
setting=c("PHC clinics","District hospital","Informal settlement / rural poor ACF","Children","PHC clinics","District hospital","Nomads","IDP / refugees","PHC clinics","District hospital","PHC clinics","District hospital","Informal settlements / rural poor ACF","PHC clinics Aracaju","PHC clinics Maceio","PHC clinics","Informal settlements ACF","Children","PHC clinics",NA),
expectedTbProp=c(paste(sep="",c(9,8,5,4,10,20,8,12,9,20,5,3,5,15,27,2,1,0,6),"%"),NA),
targetPrecision=c(paste(sep="",c(7,7,10,15,6.5,5.5,7,6,8,5.5,9,12,9,7,5.5,15,17,NA,8),"%"),NA),
expectedAttrition=c(paste(sep="",c(20,12,15,20,18,18,12,20,12,18,14,16,14,5,10,20,20,NA,20),"%"),NA),
sampleSize=c(c(1000,1000,800,500,1000,700,1000,1000,700,700,1000,1000,1000,500,500,1000,1500,500,1200),NA),
expectedAdultTB=c(72,70,34,NA,82,114,70,96,55,114,43,26,43,71,121,16,12,NA,57,1096),
adults=c(2800,rep(NA,3),3700,rep(NA,3),1400,NA,3000,rep(NA,2),1000,NA,2500,rep(NA,2),1200,14400),
children=c(500,rep(NA,3),rep(NA,4),rep(NA,2),rep(NA,3),rep(NA,2),500,rep(NA,2),NA,1000)
)
dfSSCountry[dfSSCountry=="NA%"]<-NA
dfSSCountry %>%
dplyr::select(!country) %>%
kable(row.names=FALSE,col.names=c("Country & setting","Expected proportion with TB","Target precision","Expected attrition","Sample size","Expected adults with TB","Adults","Children"),format.args = list(big.mark = ",")) %>%
kable_styling(full_width = FALSE) %>%
pack_rows("Cameroon",1,4) %>%
pack_rows("Nigeria",5,8) %>%
pack_rows("Kenya",9,10) %>%
pack_rows("Bangladesh",11,13) %>%
pack_rows("Brazil",14,15) %>%
pack_rows("Viet Nam",16,18) %>%
pack_rows("Malawi",19,19) %>%
pack_rows("TOTAL",20,20)| Country & setting | Expected proportion with TB | Target precision | Expected attrition | Sample size | Expected adults with TB | Adults | Children |
|---|---|---|---|---|---|---|---|
| Cameroon | |||||||
| PHC clinics | 9% | 7% | 20% | 1,000 | 72 | 2,800 | 500 |
| District hospital | 8% | 7% | 12% | 1,000 | 70 | . | . |
| Informal settlement / rural poor ACF | 5% | 10% | 15% | 800 | 34 | . | . |
| Children | 4% | 15% | 20% | 500 | . | . | . |
| Nigeria | |||||||
| PHC clinics | 10% | 6.5% | 18% | 1,000 | 82 | 3,700 | . |
| District hospital | 20% | 5.5% | 18% | 700 | 114 | . | . |
| Nomads | 8% | 7% | 12% | 1,000 | 70 | . | . |
| IDP / refugees | 12% | 6% | 20% | 1,000 | 96 | . | . |
| Kenya | |||||||
| PHC clinics | 9% | 8% | 12% | 700 | 55 | 1,400 | . |
| District hospital | 20% | 5.5% | 18% | 700 | 114 | . | . |
| Bangladesh | |||||||
| PHC clinics | 5% | 9% | 14% | 1,000 | 43 | 3,000 | . |
| District hospital | 3% | 12% | 16% | 1,000 | 26 | . | . |
| Informal settlements / rural poor ACF | 5% | 9% | 14% | 1,000 | 43 | . | . |
| Brazil | |||||||
| PHC clinics Aracaju | 15% | 7% | 5% | 500 | 71 | 1,000 | . |
| PHC clinics Maceio | 27% | 5.5% | 10% | 500 | 121 | . | . |
| Viet Nam | |||||||
| PHC clinics | 2% | 15% | 20% | 1,000 | 16 | 2,500 | 500 |
| Informal settlements ACF | 1% | 17% | 20% | 1,500 | 12 | . | . |
| Children | 0% | . | . | 500 | . | . | . |
| Malawi | |||||||
| PHC clinics | 6% | 8% | 20% | 1,200 | 57 | 1,200 | . |
| TOTAL | |||||||
| . | . | . | . | . | 1,096 | 14,400 | 1,000 |
3.4 Objectives
3.4.1 Primary objective
To evaluate the performance of selected TB screening tests and combinations of such tests.
3.4.2 Secondary objectives
To identify test combinations that increase the proportion of people diagnosed with microbiologically confirmed TB.
To demonstrate that combinations of current and newer TB tests can facilitate using these tests in locations where they are not currently available.
4 Data simulation
In order to demonstrate the planned analyses and show computer code, we will simulate data like the one expected to be generated by the study.
Code
set.seed(123)
sensSpecMatHiv<-data.frame(
sens=rnorm(n=7,mean=0.7,sd=0.02),
spec=rnorm(n=7,mean=0.6,sd=0.01)
)
rownames(sensSpecMatHiv)<-c("Cameroon","Nigeria","Kenya","Bangladesh","Brazil","Viet Nam","Malawi")
sensSpecMatW4ss<-data.frame(
sens=rnorm(n=7,mean=0.80,sd=0.02),
spec=rnorm(n=7,mean=0.65,sd=0.01)
)
rownames(sensSpecMatW4ss)<-c("Cameroon","Nigeria","Kenya","Bangladesh","Brazil","Viet Nam","Malawi")
sensSpecMatSsm<-data.frame(
sens=rnorm(n=7,mean=0.70,sd=0.02),
spec=rnorm(n=7,mean=0.95,sd=0.01)
)
rownames(sensSpecMatSsm)<-c("Cameroon","Nigeria","Kenya","Bangladesh","Brazil","Viet Nam","Malawi")
sensSpecMatCrp<-data.frame(
sens=rnorm(n=7,mean=0.9,sd=0.02),
spec=rnorm(n=7,mean=0.95,sd=0.01)
)
rownames(sensSpecMatCrp)<-c("Cameroon","Nigeria","Kenya","Bangladesh","Brazil","Viet Nam","Malawi")
sensSpecMatLam<-data.frame(
sens=rnorm(n=7,mean=0.82,sd=0.02),
spec=rnorm(n=7,mean=0.9,sd=0.01)
)
rownames(sensSpecMatLam)<-c("Cameroon","Nigeria","Kenya","Bangladesh","Brazil","Viet Nam","Malawi")
sensSpecMatPoolxpert<-data.frame(
sens=rnorm(n=7,mean=0.92,sd=0.01),
spec=rnorm(n=7,mean=0.97,sd=0.01)
)
rownames(sensSpecMatPoolxpert)<-c("Cameroon","Nigeria","Kenya","Bangladesh","Brazil","Viet Nam","Malawi")
sensSpecMatCxr<-data.frame(
sens=rnorm(n=7,mean=0.88,sd=0.025),
spec=rnorm(n=7,mean=0.88,sd=0.02)
)
rownames(sensSpecMatCxr)<-c("Cameroon","Nigeria","Kenya","Bangladesh","Brazil","Viet Nam","Malawi")
sensSpecMatXpert<-data.frame(
sens=rnorm(n=7,mean=0.98,sd=0.005),
spec=rnorm(n=7,mean=0.99,sd=0.005)
)
sensSpecMatXpert$sens[sensSpecMatXpert$sens>=0.99999]<-0.99999
sensSpecMatXpert$spec[sensSpecMatXpert$spec>=0.99999]<-0.99999
rownames(sensSpecMatXpert)<-c("Cameroon","Nigeria","Kenya","Bangladesh","Brazil","Viet Nam","Malawi")
dfSim<-data.frame(
PID=c(paste(sep="_","Ca",1:3300),paste(sep="_","Ni",1:3400),paste(sep="_","Ke",1:1400),paste(sep="_","Ba",1:3000),paste(sep="_","Br_Ar",1:500),paste(sep="_","Br_Ma",1:500),paste(sep="_","Vi",1:3000),paste(sep="_","Ma",1:1200)),
region=c(rep("",3300),rep("ZRC",1400),rep("JHF",2000),rep("",1400+3000),rep("Aracaju",500),rep("Maceio",500),rep("",3000+1200)),
country=c(rep("Cameroon",3300),rep("Nigeria",3400),rep("Kenya",1400),rep("Bangladesh",3000),rep("Brazil",1000),rep("Viet Nam",3000),rep("Malawi",1200)),
region=c(rep("",3300+3400+1400+3000),rep("Aracaju",500),rep("Maceio",500),rep("",3000+1200)),
setting=c(rep("PHC",1000),rep("District",1000),rep("Nomads",800),rep("Children",500),rep("PHC",700),rep("District",700),rep("Nomads",1000),rep("IDP / refugees",1000),rep("PHC",700),rep("District",700),rep("PHC",1000),rep("District",1000),rep("Informal settlements",1000),rep("PHC",1000),rep("District",1000),rep("Informal settlements",1500),rep("Children",500),rep("PHC",1200)),
reference=c(rbinom(n=1000,size=1,prob=0.09),rbinom(n=1000,size=1,prob=0.08),rbinom(n=800,size=1,prob=0.05),rbinom(n=500,size=1,prob=0.04),rbinom(n=700,size=1,prob=0.20),rbinom(n=700,size=1,prob=0.20),rbinom(n=1000,size=1,prob=0.08),rbinom(n=1000,size=1,prob=0.12),rbinom(n=700,size=1,prob=0.09),rbinom(n=700,size=1,prob=0.20),rbinom(n=1000,size=1,prob=0.05),rbinom(n=1000,size=1,prob=0.03),rbinom(n=1000,size=1,prob=0.05),rbinom(n=500,size=1,prob=0.15),rbinom(n=500,size=1,prob=0.27),rbinom(n=1000,size=1,prob=0.02),rbinom(n=1500,size=1,prob=0.01),rbinom(n=500,size=1,prob=0.001),rbinom(n=1200,size=1,prob=0.08))
) %>%
dplyr::mutate(
age=rpois(n=n(),lambda=28),
sex=sample(size=n(),c("Female","Male"),prob=c(0.5,0.5),replace=TRUE),
hiv=case_when(reference==0~rbinom(n=n(),size=1,prob=1-sensSpecMatHiv[country,"spec"]),reference==1~rbinom(n=n(),size=1,prob=sensSpecMatHiv[country,"sens"])),
w4ss=case_when(reference==0~rbinom(n=n(),size=1,prob=1-sensSpecMatW4ss[country,"spec"]),reference==1~rbinom(n=n(),size=1,prob=sensSpecMatW4ss[country,"sens"])),
ssm=case_when(reference==0~rbinom(n=n(),size=1,prob=1-sensSpecMatSsm[country,"spec"]),reference==1~rbinom(n=n(),size=1,prob=sensSpecMatSsm[country,"sens"])),
crp=case_when(reference==0~rbinom(n=n(),size=1,prob=1-sensSpecMatCrp[country,"spec"]),reference==1~rbinom(n=n(),size=1,prob=sensSpecMatCrp[country,"sens"])),
lam=case_when(reference==0~rbinom(n=n(),size=1,prob=1-sensSpecMatLam[country,"spec"]),reference==1~rbinom(n=n(),size=1,prob=sensSpecMatLam[country,"sens"])),
poolxpert=case_when(reference==0~rbinom(n=n(),size=1,prob=1-sensSpecMatPoolxpert[country,"spec"]),reference==1~rbinom(n=n(),size=1,prob=sensSpecMatPoolxpert[country,"sens"])),
cxr=case_when(reference==0~rbinom(n=n(),size=1,prob=1-sensSpecMatCxr[country,"spec"]),reference==1~rbinom(n=n(),size=1,prob=sensSpecMatCxr[country,"sens"])),
xpert=case_when(reference==0~rbinom(n=n(),size=1,prob=1-sensSpecMatXpert[country,"spec"]),reference==1~rbinom(n=n(),size=1,prob=sensSpecMatXpert[country,"sens"]))
) %>%
dplyr::mutate(
ageCentered=age-20,
)
dfAge<-rcs(dfSim$ageCentered,parms=5)
colnames(dfAge)<-paste(sep="","ageSpline",1:4)
ageKnots<-attributes(dfAge)$parms
dfSim<-dfSim %>%
dplyr::mutate(
ageSpline1=as.vector(dfAge[,1]),
ageSpline2=as.vector(dfAge[,2]),
ageSpline3=as.vector(dfAge[,3]),
ageSpline4=as.vector(dfAge[,4]),
)
dfSim[sample(size=10,replace=F,x=1:nrow(dfSim)),] %>%
kable(row.names=FALSE) %>%
kable_styling(full_width=FALSE)
write.csv(dfSim,file=paste(sep="","simData_S4A_",gsub(Sys.Date(),pattern="-",replacement=""),".csv"),row.names=F)| PID | region | country | region.1 | setting | reference | age | sex | hiv | w4ss | ssm | crp | lam | poolxpert | cxr | xpert | ageCentered | ageSpline1 | ageSpline2 | ageSpline3 | ageSpline4 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Ca_1564 | Cameroon | District | 0 | 33 | Female | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 13 | 13 | 7.5236448 | 1.7162630 | 0.3910035 | ||
| Ni_2682 | JHF | Nigeria | IDP / refugees | 0 | 21 | Male | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0.0034602 | 0.0000000 | 0.0000000 | |
| Vi_487 | Viet Nam | District | 0 | 31 | Male | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 11 | 11 | 4.6055363 | 0.7474048 | 0.0934256 | ||
| Ni_2859 | JHF | Nigeria | IDP / refugees | 0 | 28 | Female | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 8 | 8 | 1.7716263 | 0.0934256 | 0.0000000 | |
| Vi_2636 | Viet Nam | Children | 0 | 24 | Female | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 4 | 4 | 0.2214533 | 0.0000000 | 0.0000000 | ||
| Ca_2744 | Cameroon | Nomads | 0 | 31 | Female | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 11 | 11 | 4.6055363 | 0.7474048 | 0.0934256 | ||
| Ni_1782 | JHF | Nigeria | Nomads | 0 | 34 | Female | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 14 | 14 | 9.2301038 | 2.3356401 | 0.6072664 | |
| Ba_1328 | Bangladesh | District | 0 | 24 | Female | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 4 | 4 | 0.2214533 | 0.0000000 | 0.0000000 | ||
| Ba_2870 | Bangladesh | Informal settlements | 0 | 37 | Male | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 17 | 17 | 14.8823529 | 4.4844291 | 1.4013841 | ||
| Ba_2049 | Bangladesh | Informal settlements | 0 | 26 | Female | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 6 | 6 | 0.7474048 | 0.0034602 | 0.0000000 |
Table 7 shows 10 random rows from the data frame containing all 16300 simulated observations.
5 Statistical Analysis Plan
The R code to generate the results is embedded in this document. By default it is hidden, but can be displayed by clicking on the Code boxes on the right hand side.
5.1 General considerations
The reporting of this study will be prepared in accordance with the STARD and (Bossuyt et al. 2015) and STROBE (von Elm et al. 2007) guidelines.
All continuous data variables will be summarized using the following descriptive statistics:
- N (size of relevant analysis population)
- n (size of analysis population without missing values)
- proportion of complete data for each variable (n/N)
- arithmetic mean (or geometric mean if more appropriate)
- standard deviation (SD)
- median
- 25th percentile value (P25), 75th percentile value (P75) and interquartile range (IQR)
- minimum and maximum (where relevant)
The proportion / percentage of observed levels will be reported for all binary and categorical measures. When appropriate, corresponding exact 95% confidence intervals (CIs) for proportions will be included.
For statistical test, a significance level of 5% will be used. All p-values will be reported to 3 decimal digits.
5.1.1 Reporting conventions
P-values \(\geq 0.001\) and \(\leq 0.999\) will be reported to 3 decimal places; p-values less than 0.001 will be reported as “< 0.001”. The mean, standard deviation, median, IQR and other statistics will be reported to one decimal place greater than the original data. Minimum and maximum values will use the same number of decimal places as the original data. Proportions will be presented as two decimal places; values greater than zero but \(<0.01\) will be presented as “< 0.01”. Percentages will be reported to 2 decimal places; values greater than zero but \(<0.01\%\) will be presented as “< 0.01%”; values greater than \(99.99\%\) but less than \(100\%\) will be reported as “> 99.99%”. Estimated parameters, not on the same scale as raw observations (e.g. regression coefficients) will be reported to 3 significant figures.
5.1.2 Missing data
As all samples for the test diagnostics get taken at the only study visit, we expect only marginal missing data. Any missing data that does arise we expect to be due to technical reasons unrelated to the outcome of interest. However, we do expect that there will be some missing data, both for individual tests as well as for the reference standard and participant demographic and clinical data. Since we are adopting a Bayesian framework, we can easily incorporate missing data imputation as part of the MCMC process: by specifying distributions for all parameters of interest, the MCMC algorithm will consider any missing data to be no different than the unknown parameters of interest to our investigation. It will essentially impute a value for each sample at each iteration in the MCMC chains and incorporate the uncertainty of that imputation through the distribution building up over the full set of MCMC chains and iterations.
5.1.3 Technical details
The R environment for statistical computing (v4.5.0 or later) will be used for all analyses.
The Bayesian models are implemented in JAGS, v4.3.2.
All analysis code will be made publicly available under an MIT or GNU GPL v3.0 license on GitHub.
5.2 Primary objective analyses
For the primary objective we will estimate performance metrics for individual screening tests as well as combinations (“screening algorithms”) of tests. Specifically, we will estimate and report for each test and each test combination:
Sensitivity (Se)
Specificity (Sp)
Positive predictive value (PPV)
Negative predictive value (NPV)
Likelihood ratio for a positive test result (LR+) = Se/(1-Sp)
Likelihood ratio for a negative test result (LR-) = (1-Se)/Sp
Diagnostic yield per test (DYT), the proportion of positive tests
Our primary focus, from a performance point of view, will be on sensitivity and specificity, but there other metrics are of interest too, hence why we report them as well.
As we will use a Bayesian approach (see Section 5.2.5), we will estimate posterior distributions for each of these parameters, for each evaluated algorithm in each setting. We will summarise these distributions using the posterior mean and the quantile-based Bayesian confidence interval given by the 2.5th and 97.5th percentiles of the posterior distribution.
In addition to providing tables with these posterior point estimates, we will also construct forest plots showing sensitivities and specificities for each algorithm.
5.2.1 PCF / ICF / ACF analyses
Start 4 All populations use a mix of passive case finding (PCF), intensified case finding (ICF) and active finding (ACF) strategies. We will not distinguish between PCF and ICF for the purpose of the diagnostic performance evaluation; however for PCF/ICF, which are used in facility-based screening, we will distinguish between lowest level of care and district / referral level of care.
The modelling approach detailed below will be applied to each of the populations and settings for Start 4 All. What will differ however are the specific algorithms being evaluated for PCF/ICF on the one hand and ACF on the other (see further below for the list of algorithms evaluated).
5.2.2 Thresholds for diagnostic tests: CRP and CXR-CAD
We will use the following thresholds to define positive/negative status for the following assays:
Quantitative CRP:
- Positive if CRP \(\geq 5\, mg/L\), negative otherwise.
Semi-quantitative CRP:
- Positive if CRP-RDT is one of “10-40”, “40-80”, “>80”, negative if CRP-RDT is “<10”.
CXR-CAD:
- PCF/ICF: positive if CAD (Qure-ai) score \(\geq 0.5\), negative otherwise,
- ACF: positive if CAD (Qure.ai) score \(\geq 0.3\), negative otherwise.
These are the threshold we will use for the primary analysis. For secondary analyses, we will use:
- Quantitative CRP with threshold \(\geq 10\, mg/L\),
- CXR-CAD AI score with thresholds \(\geq 0.3\) (in PCF/ICF) and \(\geq 0.5\) (in ACF).
Note that for the primary analysis we will only use quantitative CRP, but sensitivity analyses will use semi-quantitative CRP and a hybrid of quantitative and semi-quantitative CRP (positive if either is positive).
5.2.3 Stratification
All analyses specified in this SAP will be for adult participants only (defined as 15 or above, though due to local regulation some countries recruited 18 or above only). While Viet Nam and Cameroon also recruited children (14 or below), there will be a separate SAP for the paediatric performance evluation.
All analyses, primary as well as secondary, will be stratified by:
- Country (but for facility-based we will also compute results pooled across countries).
- Facility-based (PCF/ICF) vs. key populations-based (ACF) recruitment.
- Within facility-based recruitment: PLWH vs people with negative or unknown HIV status (but we will also compute results for all participants regardless of HIV status).
- Within facility-based recruitment: lowest level of care vs. district level.
- Within key populations: recruitment via W4SS or CXR-CAD recruitment. We will also analysis a hybrid recruitment of either W4SS or CAD-CXR positive screening.
In summary, analyses (primary as well as secondary) will be done in the following groups:
- ACF, W4SS positive screening (separately for each country and key population).
- ACF, CAD-CXR positive screening (separately for each country and key population).
- ACF, W4SS pr CAD-CXR positive screening (separately for each country and key population).
- PCF/ICF, lowest level of care, all participants (separately per country and pooled across countries).
- PCF/ICF, lowest level of care, PLWH (separately per country and pooled across countries).
- PCF/ICF, lowest level of care, people with negative or unknown HIV status (separately per country and pooled across countries).
- PCF/ICF, district level, all participants (separately per country and pooled across countries).
- PCF/ICF, district level, PLWH (separately per country and pooled across countries).
- PCF/ICF, district level, people with negative or unknown HIV status (separately per country and pooled across countries).
5.2.4 Tuberculosis screening and diagnostic algorithms
For notation, to denote that we will use --> to refer to one assay followed by another assay and | to refer to assays being administered in parallel. In other words, combination A | B --> C --> D refers to a an algorithm where if either assay A or assay B gives a positive result (or both are positive) then proceed to assay C, and if that one is positive, then proceed to assay D (and record the outcome from that assay), else record a negative result.
5.2.4.1 PCF/ICF
We will distinguish between lowest level of care and district-level settings, but the algorithms evaluated are the same.
Xpert Ultra with pooling --> Xpert UltraXpert UltraLAMCXR-CAD --> Xpert Ultra with pooling --> Xpert UltraCRP --> Xpert Ultra with pooling --> Xpert UltraLAM --> Xpert Ultra with pooling --> Xpert UltraCXR-CAD | CRP | LAM --> Xpert Ultra with pooling --> Xpert UltraCXR-CAD | LAM --> Xpert Ultra with pooling --> Xpert UltraCRP | LAM --> Xpert Ultra with pooling --> Xpert UltraCXR-CAD | CRP --> Xpert Ultra with pooling --> Xpert UltraCXR-CAD --> Xpert UltraCRP --> Xpert UltraLAM --> Xpert UltraCXR-CAD | CRP | LAM --> Xpert UltraCXR-CAD | LAM --> Xpert UltraCRP | LAM --> Xpert UltraCXR-CAD | CRP --> Xpert UltraCXR-CAD --> LAMCRP --> LAMCXR-CAD | CRP --> LAM
5.2.4.2 2. ACF
We will distinguish between W4SS positive, CAD-CXR positive and a hybrid approach (either of W4SS, CAD-CXR positive) entry into the study. Conditional on the first step, the algorithms evaluated differ slightly depending on whether or not the first step involved CXR-CAD.
5.2.4.2.1 ACF - W4SS entry
To note that these are the exact same algorithms as for PCF/ICF (both have W4SS entry into the study).
Xpert Ultra with pooling --> Xpert UltraXpert UltraLAMCXR-CAD -> Xpert Ultra with pooling --> Xpert UltraCRP -> Xpert Ultra with pooling --> Xpert UltraLAM -> Xpert Ultra with pooling --> Xpert UltraCXR-CAD | CRP | LAM --> Xpert Ultra with pooling --> Xpert UltraCXR-CAD | LAM --> Xpert Ultra with pooling --> Xpert UltraCRP | LAM --> Xpert Ultra with pooling --> Xpert UltraCXR-CAD | CRP --> Xpert Ultra with pooling --> Xpert UltraCXR-CAD --> Xpert UltraCRP --> Xpert UltraLAM --> Xpert UltraCXR-CAD | CRP | LAM --> Xpert UltraCXR-CAD | LAM --> Xpert UltraCRP | LAM --> Xpert UltraCXR-CAD | CRP --> Xpert UltraCXR-CAD --> LAMCRP --> LAMCXR-CAD | CRP --> LAM
5.2.4.2.2 ACF - CXR-CAD entry or (CXR-CAD or W4SS) entry
The algorithms evaluated for the CXR-CAD entry to the study in ACF or the hybrid approach where either a positive W4SS screening or a positive CXR-CAD makes a participant eligible for the study are the same.
Xpert Ultra with pooling --> Xpert UltraXpert UltraLAMCRP --> Xpert Ultra with pooling --> Xpert UltraLAM --> Xpert Ultra with pooling --> Xpert UltraCRP | LAM --> Xpert Ultra with pooling --> Xpert UltraCRP --> Xpert UltraLAM --> Xpert UltraCRP | LAM --> Xpert UltraCRP --> LAM
5.2.5 Estimation
We will estimate all of the probability parameters using Bayesian statistics. In Bayesian estimation, rather than calculating point estimates for each parameter of interest, the parameters are considered to be random variables and one estimates a distribution for each parameter. In Bayesian estimation, we estimate the posterior probability density of a given parameter; posterior because it is the best-fit distribution after we have observed data. The posterior distribution summarises our beliefs about the likely values for the parameter of interest and it is an update of our beliefs about the parameter before we had observed data – the prior distribution. The data are generated by a stochastic process and we can compute the likelihood of the data under a distribution for this process. To summarise:
\[\mbox{posterior} = \mbox{prior} \times \mbox{likelihood}\]
For Phase 1 of the Start 4 All programme, the parameters we are mostly interested in sensitivities, specificities, PPVs, NPVs of individual tests and test combinations, conditional PPVs and NPVs and proportions of positive tests at each step of a test combination, TB prevalence) are all probability parameters. The exception will be the positive and negative likelihood ratios, LR+, LR-, but they can be directly derived from the sensitivities and specificieties. The natural parametric distribution for probability parameters is the beta distribution as it has support over the interval \([0,1]\).
A random variable \(X\) follows a beta distribution with parameters \(a,b\), \(X\sim\beta(a,b)\), if
\[ p(x)=\begin{cases} \frac{x^{a-1}(1-x)^{b-1}}{B(a,b)} &\mbox{ if }x\in[0,1] \\ 0 &\mbox{ otherwise} \end{cases} \]
where \(B(a,b)=\frac{\Gamma(a)\Gamma(b)}{\Gamma(a+b)}\).
The mean of this distribution is given by \(E(X)=\frac{a}{a+b}\) and the variance is \(Var(X)=\frac{a\cdot b}{(a+b)^2(a+b+1)}\). The mode is given by \(\frac{a-1}{a+b-2}\), but this is only defined if \(a,b>1\).
This means that for each probability parameter we plan to estimate within Start 4 All, we can assume a beta prior distribution, \(p\sim\beta(a,b)\), where \(p\) is the probability parameter of interest. The corresponding data likelihood will be a binomial likelihood \(X\sim Bin(n,p)\), where \(X\) is the number of positive results (possibly conditional on prior tests), \(n\) the corresponding total number of observations (aka the denominator) and \(p\) the same probability parameter as in the prior. One can show that the posterior will also be a beta distribution (since the beta is the conjugate prior for a binomial likelihood) with a closed form solution: \(p|X=k\sim\beta(k+a,n-k+b)\). The closed-form solution is computationally fast to compute - no need to use Markov Chain Monte Carlo (MCMC) or Integrated Nested Lapace Approximation (INLA).
For prior, a weakly informative prior can be used, for example the Kerman prior \(\beta(1/3,1/3)\) (Kerman 2011) or the improper Haldane prior \(\beta(0,0)\) (Haldane 1948). The latter has the advantage that it essentially does not provide any prior information and the posterior mean corresponds exactly to the sample mean. The drawback of the Haldane prior is, however, that where k=0 or k=n, it yields an improper posterior distribution. Another drawback is that JAGS, the MCMC sampler we are using, does not allow improper priors. For this reason, we will use the Kerman prior.
Specifically, with the Kerman prior, for a probability parameter of interest \(p\), if we observe \(X=k\) positive results out of \(n\) total results, then the posterior distribution will be a beta distribution with parameters \(k+a=k+1/3\) and \(n-k+b=n-k+1/3\):
\[p|n,X=k\sim\beta(k+a,n-k+b)\]
The distributional parameters \(\alpha=k+a, \beta=n-k+b\) for the posterior will then be directly fed into the health economic modelling to guarantee correct propagation of errors.
The data we will collect is expected to be incomplete - some individuals will have missing results for some of the tests and some may even lack a reference test result, meaning we would not know their TB status.
For these reasons, we will use a hybrid approach, using both the closed form result from above as well as Markov Chain Monte Carlo (MCMC) estimation and modelling directly the individual test results for each test for each participant from each country and setting in the study.
To note that, when we use MCMC, only a relatively small subset of probability parameters (TB prevalence, sensitivities and specificities of individual tests) will generate all of the data, and we can, in theory, derive any and all conditional probability parameters (e.g. P(positive LAM | positive CAD-CXR)) directly from this small subset. However this requires some assumptions, specifically that conditional on TB status, the different tests are independent. For Xpert and pooled Xpert, which use the same technology, this can easily be seen not to be true and so we will still derive all conditional parameters individually, but using the MCMC process to impute the missing data while incorporating the uncertainty of these imputations into our estimations.
All Bayesian models will be implemented in JAGS, we will run 4 chains, with each chain run for 3,000 adaptive iterations, 1,000 burn-in iterations and 12,000 iterations that are retained for statistical inference. Depending on MCMC diagnostics for mixing and non-convergence, we may run more chains for longer if needed. (Note that the mock-ups in this SAP, for convenience, used only 4 chains, 1,000 adaptive iterations, 500 burn-in iterations and 2,000 iterations for inference.)
5.2.5.1 Per-country analysis
We will assume that the individual probability parameters are random variables. We will further assume that the set of sensitivity and specificity parameters for the different tests follow a non-trivial joint distribution and we will specify this in the MCMC model.
Let:
- \(N\) be the number of participants in the study,
- \(m=5\) be the number of tests / assays being evaluated,
- \(T_i, i=1,\ldots,N\) be a binary variable recording the TB status of the \(i^{th}\) study participant (for the purpose of Start 4 All we take this as the result of the microbiological confirmation / reference test),
- \(X_{j,i}, j=\mbox{cxr, crp, lam, pXpert, sXpert}, i=1,\ldots,N\) be the individual test results for the different participants,
- \(p_{se,j}\), \(p_{sp,j}\) be the sensitivity and specificity of test \(j\),
- \(p_{TB}\) be the prevalence of TB in the population.
With this notation, we can write down the assumptions of the Bayesian MCMC estimation:
- TB status is Bernoulli distributed.
\[T_i\sim\mbox{Bernoulli}(p_{TB})\] with \(\mbox{logit}(p_{TB})=\beta_0+\beta_{s}\cdot\mbox{sex}+\beta_{h}\cdot\mbox{hiv}+\mathbb{\beta}_a\cdot s(\mbox{age})\), assuming weakly informative \(\cal{N}(0,10)\) priors for the \(\beta_j\) parameters. \(s()\) indicates a restricted cubic / natural spline with 5 knots and \(\mathbb{\beta}_a\) is the corresponding vector of parameters. For the analyses stratified by HIV status, the HIV term is dropped from the linear predictor term.
- Individual test results are Bernoulli distributed, conditional on TB status.
\[X_{j,i}\sim\left\{ \begin{array}{ll} \mbox{Bernoulli}(p_{se,j}) & \quad\mbox{ if }T_i=1 \\ \mbox{Bernoulli}(1-p_{sp,j}) & \quad\mbox{ if }T_i=0 \end{array} \right. \]
- Sensitivities, specificities are specified as the inverse logits of real scalars.
\[ \begin{array}{lll} p_{se,j} &=& \mbox{logit}^{-1}(z_{se,j}) \\ p_{sp,j} &=& \mbox{logit}^{-1}(z_{sp,j}) \end{array} \]
- These, or in other words, the logits of sensitivities, specificities, follow a non-trivial joint multivariate normal distribution.
\[\mathbb{z}=(z_{se,w4ss},z_{sp,w4ss},z_{se,cxr},z_{sp,cxr},\ldots,z_{se,sXpert},z_{sp,sXpert})\sim MV\cal{N}(\mathbb{\mu},\mathbb{\Sigma})\]
- Priors for the means of the logits are weakly informative.
\[ \begin{array}{lll} \mu_{se,j}\sim\cal{N}(0,10) \\ \mu_{sp,j}\sim\cal{N}(0,10) \end{array} \]
- Prior for the covariance matrix follow a satndard prior distribution for covariance matrices.
\[\Sigma\sim\mbox{invWishart}(\Lambda,\eta)\qquad \Lambda=I,\; \eta=2\cdot m+1\]
Assuming that all dependencies between tests are captured through the above joint distribution of sensitivities and specificities and through conditioning on TB status, then all other, conditional, probability parameters can be derived from the sensitivity and specificity parameters. However, as explained earlier, the assumption of conditional independence is most likely unreasonable. For this reason, for each conditional parameter \(\pi|\mathbf{T}\) (where \(\mathbf{T}\) denote all test results upon which the probability parameter is conditional on), we will assume:
\(\pi|\mathbf{T}\sim\beta(a=K+1/3,b=M-K+1/3)\)
\(M,K\) are the random variables for the count of records for which the parameter is being evaluated (M) and the count of positive results (K) respectively and they are derived from the MCMC process (specifically \(T_i, X_{i,j}\)).
This final distribution for \(\pi|\mathbf{T}\) is not necessarily a beta distribution itself (since M and K are random themselves). For the performance evaluation, we will report the distribution as is. However to feed this posterior distribution into the health economic modelling, we will assume that it can be approximated by one. We will use quantile-matching to identify the best-fitting beta distribution for the resulting empirical distribution from the MCMC output. The beta distribution parameters from this best-fit beta distribution are then entered into the health economic modelling.
5.2.5.2 Pooled PCF/ICF analysis at lowest level of care
For facility-based screening, we will pool the data from all Start 4 All partner countries to estimate a single set of performance metrics at i) lowest level of care and ii) district-level care.
There is a need to account for country-level variation in the estimation procedure described above.
Let:
- \(N\) be the number of participants in the study,
- \(m=5\) be the number of tests / assays being evaluated,
- \(T_{l,i}\) be a binary variable recording the TB status of the \(i^{th}\) study participant from country \(l\),
- \(X_{l,j,i}\) be the individual test result for participant \(i\) from country \(l\) for assay \(j\),
- \(p_{se,l,j}\), \(p_{sp,l,j}\) be the sensitivity and specificity of test \(j\) in country \(l\),
- \(p_{TB,l}\) be the prevalence of TB in the population in country \(l\).
where the indices \({i,j,l}\) iterate over:
- \(l=\mbox{Bangladesh, Brazil, Cameroon, Kenya, Malawi, Nigeria, Viet Nam}\),
- \(j=\mbox{cxr, crp, lam, pXpert, sXpert}\),
- \(i=1,\ldots,N\)
With this notation, we can write down the assumptions for the Bayesian MCMC estimation:
- TB status is Bernoulli distributed.
\[T_{l,i}\sim\mbox{Bernoulli}(p_{TB,l})\] with \(\mbox{logit}(p_{TB})=\beta_0+\beta_{s}\cdot\mbox{sex}+\beta_{h}\cdot\mbox{hiv}+\mathbb{\beta}_a\cdot s(\mbox{age})\), assuming weakly informative \(\cal{N}(0,10)\) priors for the \(\beta_j\) parameters. \(s()\) indicates a restricted cubic / natural spline with 5 knots and \(\mathbb{\beta}_a\) is the corresponding vector of parameters. For the analyses stratified by HIV status, the HIV term is dropped from the linear predictor term.
- Individual test results are Bernoulli distributed, conditional on TB status.
\[ X_{l,j,i}\sim\left\{ \begin{array}{ll} \mbox{Bernoulli}(p_{se,l,j}) & \quad\mbox{ if }T_{l,i}=1 \\ \mbox{Bernoulli}(1-p_{sp,l,j}) & \quad\mbox{ if }T_{l,i}=0 \end{array} \right. \]
- Sensitivities, specificities are specified as the inverse logits of real scalars.
\[ \begin{array}{lll} p_{se,l,j} &=& \mbox{logit}^{-1}(z_{se,j}+\tau_{l,j}) \\ p_{sp,l,j} &=& \mbox{logit}^{-1}(z_{sp,j}+\nu_{l,j}) \end{array} \]
where \(\tau_{l,j}, \nu_{l,j}\) are country-level random effects.
- These, or in other words, the logits of sensitivities, specificities, follow a non-trivial joint multivariate normal distribution.
\[ \mathbb{z}=(z_{se,w4ss},z_{sp,w4ss},z_{se,cxr},z_{sp,cxr},\ldots,z_{se,sXpert},z_{sp,sXpert})\sim MV\cal{N}(\mathbb{\mu},\mathbb{\Sigma}) \]
- Priors for the means of the logits are weakly informative.
\[ \begin{array}{lll} \mu_{se,j}\sim\cal{N}(0,10) \\ \mu_{sp,j}\sim\cal{N}(0,10) \end{array} \]
- Prior for the covariance matrix follow a standard prior distribution for covariance matrices.
\[ \Sigma\sim\mbox{invWishart}(\Lambda,\eta)\qquad \Lambda=I,\; \eta=2\cdot m+1 \]
Assuming that all dependencies between tests are captured through the above joint distribution of sensitivities and specificities and through conditioning on TB status, then all other, conditional, probability parameters can be derived from the sensitivity and specificity parameters. However, as explained earlier, the assumption of conditional independence is most likely unreasonable. For this reason, for each conditional parameter \(\pi|\mathbf{T}\) (where \(\mathbf{T}\) denote all test results upon which the probability parameter is conditional on), we will assume:
\(\pi|\mathbf{T}\sim\beta(a=K+1/3,b=M-K+1/3)\)
\(M,K\) are the random variables for the count of records for which the parameter is being evaluated (M) and the count of positive results (K) respectively and they are derived from the MCMC process (specifically \(T_{l,i}, X_{l,j,i}\)).
This final distribution for \(\pi|\mathbf{T}\) is not necessarily a beta distribution itself (since M and K are random themselves). For the performance evaluation, we will report the distribution as is. However to feed this posterior distribution into the health economic modelling, we will assume that it can be approximated by one. We will use quantile-matching to identify the best-fitting beta distribution for the resulting empirical distribution from the MCMC output. The beta distribution parameters from this best-fit beta distribution are then entered into the health economic modelling.
5.2.5.3 Model diagnostics
For every Bayesian model fitted, we will check for signs of non-convergence of the MCMC algorithm. Specifically we will:
Inspect trace plots for all parameters (and, if needed, increase the number of chains and/or iterations per chain).
Compute Gelman-Rubin potential scale reduction factors for all parameters (and, if needed, increase the number of iterations).
Compute effect sample sizes for every parameter (and, if needed, increase the number of iterations).
Compute posterior predictive checks to assess the goodness of fit of the model.
5.3 Secondary analyses
These will include:
Repeating the main analysis but with alternative threshold for quantitative CRP and CXR-CAD AI score (see Section 5.2.2).
Using a composite reference standard of culture and molecular testing.
Modelling performance as a function of TB prevalence.
5.4 Sensitivity analyses
We will explore (see Section 5.2.2) using semi-quantitative CRP instead of quantitative CRP as well as a hybrid of quantitative and semi-quantitative CRP.
5.5 Mock results
This version of the SAP includes some mock-ups but not yet all mock-ups as they needed to be re-done completely given the change in algorithms being evaluated. While the analysis plan itself is complete, full mock-ups will only be included in a future version.
Code
parsVectW4ss<-as.vector(unlist(read.csv(header=F,"../../output/20250527/parameters_forRscript_w4ss.txt")[1,]))
parsVectCxr<-as.vector(unlist(read.csv(header=F,"../../output/20250527/parameters_forRscript_cxr.txt")[1,]))
parsListW4ss.ab<-character(0)
for(par in parsVectW4ss){
if(par=="ptb"){
parsListW4ss.ab<-c(parsListW4ss.ab,"ptb.a","ptb.b")
}else{
tmp<-unlist(strsplit(split="\\.",par))
parsListW4ss.ab<-c(parsListW4ss.ab,paste(sep=".",tmp[1],"a",paste(collapse=".",tmp[-1])),paste(sep=".",tmp[1],"b",paste(collapse=".",tmp[-1])))
}
}
parsListCxr.ab<-character(0)
for(par in parsVectCxr){
if(par=="ptb"){
parsListCxr.ab<-c(parsListCxr.ab,"ptb.a","ptb.b")
}else{
tmp<-unlist(strsplit(split="\\.",par))
parsListCxr.ab<-c(parsListCxr.ab,paste(sep=".",tmp[1],"a",paste(collapse=".",tmp[-1])),paste(sep=".",tmp[1],"b",paste(collapse=".",tmp[-1])))
}
}
jagsFileW4ss<-"../../scripts/S4A_jagsPerformanceModel_entryW4SS_20250527_clean.jags"
jagsFileW4ssNoHiv<-"../../scripts/S4A_jagsPerformanceModel_entryW4SS_20250527_clean.noHIVstatus.jags"
jagsFileCxr<-"../../scripts/S4A_jagsPerformanceModel_entryCXR_20250527_clean.jags"
jagsFileCxr.NoHiv<-"../../scripts/S4A_jagsPerformanceModel_entryCXR_20250527_clean.noHIVstatus.jags"
jagsFileW4ssPooled<-"../../scripts/S4A_jagsPerformanceModel_entryW4SS_pooledFacility_20250527_clean.jags"
jagsFileW4ssPooled.NoHiv<-"../../scripts/S4A_jagsPerformanceModel_entryW4SS_pooledFacility_20250527_clean.noHIVstatus.jags"
nChains<-4
nAdapt<-1000 # 3000 in full analysis
nBurn<-500 # 1000 in full analysis
nIter<-2000 # 12000 in full analysis
# define the parameters to extract from the MCMC run
parsVectW4ssNoLR<-parsVectW4ss
parsVectW4ss<-c(parsVectW4ss,gsub(pattern="pse",replacement="lrp",grep(value=TRUE,pattern="pse",parsVectW4ss)),gsub(pattern="pse",replacement="lrm",grep(value=TRUE,pattern="pse",parsVectW4ss)))
parsVectCxrNoLR<-parsVectCxr
parsVectCxr<-c(parsVectCxr,gsub(pattern="pse",replacement="lrp",grep(value=TRUE,pattern="pse",parsVectCxr)),gsub(pattern="pse",replacement="lrm",grep(value=TRUE,pattern="pse",parsVectCxr)))
# helper functions to process MCMC output
ssBetaPars<-function(abPars, probs, parData, alpha = 0.05) {
res<-sum((qbeta(probs,abPars[1],abPars[2])-quantile(parData,probs=probs))^2)
return(res)
}
identifyBetaPars<-function(probs=c(0.025,0.25,0.5,0.75,0.975), parData, maxiter = 1000){
if (length(probs)<2 | sum(probs<0 | probs>1)>0) {
stop("There need to be at least 2 probs parameters and the probs parameters need all to be contained within [0,1].")
}
m<-mean(parData)
s<-var(parData)
initPars<-c(m*(m*(1-m)/s-1),(1-m)*(m*(1-m)/s-1))
res <- suppressWarnings(optim(fn = ssBetaPars, probs=probs, parData=parData, par = initPars, control = list(maxit = maxiter), alpha = alpha))
if (res$convergence != 0) {
stop("optim() as called by identifyBetaPars() failed to converge.")
}
return(res$par)
}
getBetaDistsFromMCMC<-function(mcmcPars,doPlot=FALSE,plotFile="s4a_mcmcPars.pdf"){
parsAll<-colnames(mcmcPars[[1]])
pars<-parsAll[!grepl(parsAll,pattern="lrm|lrp") & !(parsAll %in% c(paste(sep="","b",0:2),paste(sep="","bs",1:4)))]
nChains<-length(mcmcPars)
g<-list()
resDf<-data.frame(
par=pars,
a=NA,
b=NA,
distMean=NA,
dataMean=NA
)
parsDf<-mcmcPars[[1]]
if(nChains>1){
for(j in 2:nChains){
parsDf<-rbind(parsDf,mcmcPars[[j]])
}
}
for(par in pars){
tmpPars<-identifyBetaPars(parData=parsDf[,par])
resDf$a[resDf$par==par]<-tmpPars[1]
resDf$b[resDf$par==par]<-tmpPars[2]
resDf$dataMean[resDf$par==par]<-mean(parsDf[,par])
}
if(doPlot){
pdf(width=4*2,height=4*ceiling(length(pars)/2),file=plotFile)
par(mfrow=c(ceiling(length(pars)/2),2))
for(par in parsAll){
hist(freq=FALSE,parsDf[,par],breaks=100,xlab=par,ylab="density")
if(par %in% pars){
xx<-seq(min(parsDf[,par]),max(parsDf[,par]),length=1e4)
yy<-dbeta(xx,resDf$a[resDf$par==par],resDf$b[resDf$par==par])
lines(xx,yy,lwd=2,col="steelblue")
}
}
dev.off()
}
resDf$distMean<-resDf$a/(resDf$a+resDf$b)
return(resDf)
}
# analysis function
analysisFunBayesBetaPars<-function(dat,c,r,s,doPlot=FALSE,plotFile="s4a_mcmcPars.pdf",nChains=nChains,nAdapt=nAdapt,nBurn=nBurn,nIter=nIter,jagsFile,parsVect){
# dat = data frame with the data; requires columns country, region, setting, reference, hiv, w4ss, crp, lam, poolxpert, cxr, xpert
# c = country
# r = region
# s = setting
# doPlot = (logical) idnicatees whether or not to plot the MCMC trace plots and posterior distributions; defaults to FALSE
# plotFile = filename for the graph (if doPlot==TRUE)
# nChains, nAdapt, nBurn, nIter = MCMC parameters (number of chains, adaptation iterations, burn-in iterations, MCMC iterations)
# jagsFile = filename with path to the JAGS model file
# parsVect = vector with parameters to extract from / monitor during the MCMC sampling
# prepare the data
dfTmp<-dat %>%
dplyr::filter(country==c & region==r & setting==s)
datJags<-list(
N=nrow(dfTmp),
hiv=dfTmp$hiv,
sexM=ifelse(dfTmp$sex=="Male",1,0),
ageSpline1=dfTmp$ageSpline1,
ageSpline2=dfTmp$ageSpline2,
ageSpline3=dfTmp$ageSpline3,
ageSpline4=dfTmp$ageSpline4,
reference=dfTmp$reference,
crp=dfTmp$crp,
cxr=dfTmp$cxr,
lam=dfTmp$lam,
poolxpert=dfTmp$poolxpert,
xpert=dfTmp$xpert,
ssm=dfTmp$ssm
)
# run the JAGS model
jagsModel <- jags.model(jagsFile, data=datJags, n.chains = nChains, n.adapt = nAdapt, quiet = TRUE)
update(jagsModel,nBurn)
parsModel<-coda.samples(model=jagsModel,variable.names=parsVect,n.iter = nIter, na.rm=FALSE)
# process the MCMC results
betaPars<-getBetaDistsFromMCMC(mcmcPars=parsModel,doPlot=doPlot,plotFile=plotFile)
# return the results
return(list(mcmcObj=parsModel,betaPars=betaPars))
}
analysisFunBayesBetaParsPool<-function(dat,set,doPlot=FALSE,plotFile="s4a_mcmcPars_pool.pdf",nChains=nChains,nAdapt=nAdapt,nBurn=nBurn,nIter=nIter,jagsFile,parsVect){
# dat = data frame with the data; requires columns country, region, setting, reference, hiv, w4ss, crp, lam, poolxpert, cxr, xpert
# set = PHC or District
# doPlot = (logical) idnicatees whether or not to plot the MCMC trace plots and posterior distributions; defaults to FALSE
# plotFile = filename for the graph (if doPlot==TRUE)
# nChains, nAdapt, nBurn, nIter = MCMC parameters (number of chains, adaptation iterations, burn-in iterations, MCMC iterations)
# jagsFile = filename with path to the JAGS model file
# parsVect = vector with parameters to extract from / monitor during the MCMC sampling
# prepare the data
dfTmp<-dat %>%
dplyr::filter(setting==set) %>%
dplyr::mutate(
site=as.integer(factor(
paste(sep="",country,region)
))
)
datJags<-list(
N=nrow(dfTmp),
nsites=length(unique(dfTmp$site)),
site=dfTmp$site,
hiv=dfTmp$hiv,
ageSpline1=dfTmp$ageSpline1,
ageSpline2=dfTmp$ageSpline2,
ageSpline3=dfTmp$ageSpline3,
ageSpline4=dfTmp$ageSpline4,
sexM=ifelse(dfTmp$sex=="Male",1,0),
reference=dfTmp$reference,
crp=dfTmp$crp,
cxr=dfTmp$cxr,
lam=dfTmp$lam,
poolxpert=dfTmp$poolxpert,
xpert=dfTmp$xpert,
ssm=dfTmp$ssm
)
# run the JAGS model
jagsModel <- jags.model(jagsFile, data=datJags, n.chains = nChains, n.adapt = nAdapt, quiet = TRUE)
update(jagsModel,nBurn)
parsModel<-coda.samples(model=jagsModel,variable.names=parsVect,n.iter = nIter, na.rm=FALSE)
# process the MCMC results
betaPars<-getBetaDistsFromMCMC(mcmcPars=parsModel,doPlot=doPlot,plotFile=plotFile)
# return the results
return(list(mcmcObj=parsModel,betaPars=betaPars))
}
getLRpLRm<-function(mcmcObj){
nChains<-length(mcmcObj)
for(j in 1:nChains){
pars<-colnames(mcmcObj[[j]])
pars<-gsub(pattern="pse",replacement="",pars[grepl(pattern="pse.",pars)])
x.thin<-thin(mcmcObj[[j]])
x.start<-start(mcmcObj[[j]])
x.end<-end(mcmcObj[[j]])
for(par in pars){
pse<-mcmcObj[[j]][,paste(sep="","pse",par)]
psp<-mcmcObj[[j]][,paste(sep="","psp",par)]
mcmcObj[[j]]<-as.data.frame(mcmcObj[[j]]) %>%
dplyr::mutate(
!!paste(sep="","lrp",par) := pse/(1-ifelse(psp<0.99999,psp,0.99999)),
!!paste(sep="","lrm",par) := (1-pse)/psp
)
}
mcmcObj[[j]]<-mcmc(data=as.matrix(mcmcObj[[j]]),start=x.start,end=x.end,thin=x.thin)
}
return(mcmcObj)
}
gr<-expand.grid(c("pse","psp","ppv","npv","dyt","posProp","lrm","lrp"),c("Crp","Cxr","Lam","Poolxpert","Xpert","Ssm"))
parsVectPrim<-apply(MARGIN=1,FUN=paste,gr,collapse=".")5.5.1 Descriptive statistics and summary statistics
We will summarise the collected data in a simple table as shown on Table 8.
Code
pTB<-mean(dfSim$reference,na.rm=T)
pTBCI<-binom.test(n=sum(!is.na(dfSim$reference)),x=sum(dfSim$reference,na.rm=TRUE))$conf.int
n<-nrow(dfSim)
nMissRef<-sum(is.na(dfSim$reference))
nMissAnyDiag<-sum(rowSums(is.na(dfSim[,c("reference","w4ss","crp","cxr","lam","xpert","poolxpert","ssm")]))>0)
dfSum<-data.frame(
country="Any",
setting="Any",
n=n,
nWithReference=sum(!is.na(dfSim$reference)),
nTB=sum(dfSim$reference,na.rm=T),
pTB=paste(sep="",format(nsmall=2,round(digits=2,100*pTB)),"% (",format(nsmall=2,round(digits=2,100*pTBCI[1])),"%,",format(nsmall=2,round(digits=2,100*pTBCI[2])),"%)"),
missingRef=paste(sep="",nMissRef," (",format(nsmall=2,round(digits=2,100*nMissRef/n)),"%)"),
missingAnyDiag=paste(sep="",nMissAnyDiag," (",format(nsmall=2,round(digits=2,100*nMissAnyDiag/n)),"%)")
)
dfSumStratified<-dfSim %>%
dplyr::filter(country!="" & !is.na(setting)) %>%
dplyr::group_by(country,setting) %>%
dplyr::summarise(
n=n(),
nWithReference=sum(!is.na(reference)),
nTB=sum(reference,na.rm=TRUE),
pTB=ifelse(sum(!is.na(reference)>0),paste(sep="",format(nsmall=2,round(digits=2,100*mean(reference,na.rm=TRUE))),"%"," (",format(nsmall=2,round(digits=2,100*binom.test(x=sum(reference,na.rm=TRUE),n=sum(!is.na(reference)))$conf.int[1])),"%,",format(nsmall=2,round(digits=2,100*binom.test(x=sum(reference,na.rm=TRUE),n=sum(!is.na(reference)))$conf.int[2])),"%)"),NA),
missingRef=paste(sep="",sum(is.na(reference))," (",format(nsmall=2,round(digits=2,100*sum(is.na(reference))/n())),"%)"),
missingAnyDiag=paste(sep="",sum(is.na(reference+w4ss+crp+cxr+lam+xpert+poolxpert+ssm))," (",format(nsmall=2,round(digits=2,100*sum(is.na(reference+w4ss+crp+cxr+lam+xpert+poolxpert+ssm))/n())),"%)"),
.groups="drop"
)
dfSum<-rbind(dfSum,dfSumStratified)
dfSum %>%
kable(col.names=c("Country","Setting","n","n (with available reference)","TB cases (culture)","TB prevalence (95% CI)","Culture not available (%)","Observations with at least one diagnostic missing (%)")) %>%
kable_styling(full_width=FALSE)| Country | Setting | n | n (with available reference) | TB cases (culture) | TB prevalence (95% CI) | Culture not available (%) | Observations with at least one diagnostic missing (%) |
|---|---|---|---|---|---|---|---|
| Any | Any | 16300 | 16300 | 1311 | 8.04% (7.63%,8.47%) | 0 (0.00%) | 0 (0.00%) |
| Bangladesh | District | 1000 | 1000 | 25 | 2.50% (1.62%,3.67%) | 0 (0.00%) | 0 (0.00%) |
| Bangladesh | Informal settlements | 1000 | 1000 | 49 | 4.90% (3.65%,6.43%) | 0 (0.00%) | 0 (0.00%) |
| Bangladesh | PHC | 1000 | 1000 | 34 | 3.40% (2.37%,4.72%) | 0 (0.00%) | 0 (0.00%) |
| Brazil | PHC | 1000 | 1000 | 215 | 21.50% (18.99%,24.18%) | 0 (0.00%) | 0 (0.00%) |
| Cameroon | Children | 500 | 500 | 17 | 3.40% (1.99%,5.39%) | 0 (0.00%) | 0 (0.00%) |
| Cameroon | District | 1000 | 1000 | 85 | 8.50% (6.85%,10.40%) | 0 (0.00%) | 0 (0.00%) |
| Cameroon | Nomads | 800 | 800 | 30 | 3.75% (2.54%,5.31%) | 0 (0.00%) | 0 (0.00%) |
| Cameroon | PHC | 1000 | 1000 | 79 | 7.90% (6.30%,9.75%) | 0 (0.00%) | 0 (0.00%) |
| Kenya | District | 700 | 700 | 138 | 19.71% (16.83%,22.86%) | 0 (0.00%) | 0 (0.00%) |
| Kenya | PHC | 700 | 700 | 59 | 8.43% (6.48%,10.74%) | 0 (0.00%) | 0 (0.00%) |
| Malawi | PHC | 1200 | 1200 | 93 | 7.75% (6.30%,9.41%) | 0 (0.00%) | 0 (0.00%) |
| Nigeria | District | 700 | 700 | 119 | 17.00% (14.29%,19.99%) | 0 (0.00%) | 0 (0.00%) |
| Nigeria | IDP / refugees | 1000 | 1000 | 117 | 11.70% (9.77%,13.86%) | 0 (0.00%) | 0 (0.00%) |
| Nigeria | Nomads | 1000 | 1000 | 77 | 7.70% (6.12%,9.53%) | 0 (0.00%) | 0 (0.00%) |
| Nigeria | PHC | 700 | 700 | 153 | 21.86% (18.85%,25.11%) | 0 (0.00%) | 0 (0.00%) |
| Viet Nam | Children | 500 | 500 | 0 | 0.00% (0.00%,0.74%) | 0 (0.00%) | 0 (0.00%) |
| Viet Nam | District | 1000 | 1000 | 10 | 1.00% (0.48%,1.83%) | 0 (0.00%) | 0 (0.00%) |
| Viet Nam | Informal settlements | 1500 | 1500 | 11 | 0.73% (0.37%,1.31%) | 0 (0.00%) | 0 (0.00%) |
We will also tabulate the performance of individual tests per country and setting for two different reference standards (culture or Xpert Ultra).
Code
gr<-expand.grid(c("culture","xpert"),c("All","PLWithHIV","PLWithoutHIV"),unique(paste(sep="_",dfSim$country,dfSim$region,dfSim$setting)))
gr[,1]<-as.character(gr[,1])
gr[,2]<-as.character(gr[,2])
gr[,3]<-as.character(gr[,3])
dfPerf<-data.frame(
Country=NA,
Region=NA,
Setting=NA,
CRS=gr[,3],
Reference=gr[,1],
Population=gr[,2],
Prevalence=NA,
cultNegXpertNeg=NA,
cultPosXpertNeg=NA,
cultNegXpertPos=NA,
cultPosXpertPos=NA,
cxr_sens=NA,
cxr_spec=NA,
crp_sens=NA,
crp_spec=NA,
lam_sens=NA,
lam_spec=NA,
ssm_sens=NA,
ssm_spec=NA,
poolxpert_sens=NA,
poolxpert_spec=NA,
xpert_sens=NA,
xpert_spec=NA
)
for(j in 1:nrow(dfPerf)){
dfPerf$Country[j]<-unlist(strsplit(split="_",dfPerf$CRS[j]))[1]
dfPerf$Region[j]<-unlist(strsplit(split="_",dfPerf$CRS[j]))[2]
dfPerf$Setting[j]<-unlist(strsplit(split="_",dfPerf$CRS[j]))[3]
dfTmp<-dfSim %>%
dplyr::filter(country==dfPerf$Country[j] & region==dfPerf$Region[j] & setting==dfPerf$Setting[j])
if(dfPerf$Population[j]=="PLWithHIV"){
dfTmp<-dfTmp %>%
dplyr::filter(!is.na(hiv) & hiv==1)
}else if(dfPerf$Population[j]=="PLWithoutHIV"){
dfTmp<-dfTmp %>%
dplyr::filter(!is.na(hiv) & hiv==0)
}
if(dfPerf$Reference[j]=="culture"){refTmp<-dfTmp$reference}else{refTmp<-dfTmp$xpert}
k<-sum(na.rm=TRUE,refTmp)
n<-sum(!is.na(refTmp))
dfPerf$Prevalence[j]<-paste(sep="",format(nsmall=1,round(digits=1,100*k/n)),"% (",k,"/",n,")")
dfPerf$cultNegXpertNeg[j]<-sum(!is.na(dfTmp$reference) & !is.na(dfTmp$xpert) & dfTmp$reference==0 & dfTmp$xpert==0)
dfPerf$cultPosXpertNeg[j]<-sum(!is.na(dfTmp$reference) & !is.na(dfTmp$xpert) & dfTmp$reference==1 & dfTmp$xpert==0)
dfPerf$cultNegXpertPos[j]<-sum(!is.na(dfTmp$reference) & !is.na(dfTmp$xpert) & dfTmp$reference==0 & dfTmp$xpert==1)
dfPerf$cultPosXpertPos[j]<-sum(!is.na(dfTmp$reference) & !is.na(dfTmp$xpert) & dfTmp$reference==1 & dfTmp$xpert==1)
#CXR
tp<-sum(na.rm=TRUE,refTmp*dfTmp$cxr)
fp<-sum(na.rm=TRUE,(1-refTmp)*dfTmp$cxr)
tn<-sum(na.rm=TRUE,(1-refTmp)*(1-dfTmp$cxr))
fn<-sum(na.rm=TRUE,refTmp*(1-dfTmp$cxr))
dfPerf$cxr_sens[j]<-paste(sep="",format(nsmall=1,round(digits=1,100*tp/(tp+fn))),"% (",tp,"/",tp+fn,")")
dfPerf$cxr_spec[j]<-paste(sep="",format(nsmall=1,round(digits=1,100*tn/(tn+fp))),"% (",tn,"/",tn+fp,")")
#CRP
tp<-sum(na.rm=TRUE,refTmp*dfTmp$crp)
fp<-sum(na.rm=TRUE,(1-refTmp)*dfTmp$crp)
tn<-sum(na.rm=TRUE,(1-refTmp)*(1-dfTmp$crp))
fn<-sum(na.rm=TRUE,refTmp*(1-dfTmp$crp))
dfPerf$crp_sens[j]<-paste(sep="",format(nsmall=1,round(digits=1,100*tp/(tp+fn))),"% (",tp,"/",tp+fn,")")
dfPerf$crp_spec[j]<-paste(sep="",format(nsmall=1,round(digits=1,100*tn/(tn+fp))),"% (",tn,"/",tn+fp,")")
#LAM
tp<-sum(na.rm=TRUE,refTmp*dfTmp$lam)
fp<-sum(na.rm=TRUE,(1-refTmp)*dfTmp$lam)
tn<-sum(na.rm=TRUE,(1-refTmp)*(1-dfTmp$lam))
fn<-sum(na.rm=TRUE,refTmp*(1-dfTmp$lam))
dfPerf$lam_sens[j]<-paste(sep="",format(nsmall=1,round(digits=1,100*tp/(tp+fn))),"% (",tp,"/",tp+fn,")")
dfPerf$lam_spec[j]<-paste(sep="",format(nsmall=1,round(digits=1,100*tn/(tn+fp))),"% (",tn,"/",tn+fp,")")
#SSM
tp<-sum(na.rm=TRUE,refTmp*dfTmp$ssm)
fp<-sum(na.rm=TRUE,(1-refTmp)*dfTmp$ssm)
tn<-sum(na.rm=TRUE,(1-refTmp)*(1-dfTmp$ssm))
fn<-sum(na.rm=TRUE,refTmp*(1-dfTmp$ssm))
dfPerf$ssm_sens[j]<-paste(sep="",format(nsmall=1,round(digits=1,100*tp/(tp+fn))),"% (",tp,"/",tp+fn,")")
dfPerf$ssm_spec[j]<-paste(sep="",format(nsmall=1,round(digits=1,100*tn/(tn+fp))),"% (",tn,"/",tn+fp,")")
#XPERT POOLED
tp<-sum(na.rm=TRUE,refTmp*dfTmp$poolxpert)
fp<-sum(na.rm=TRUE,(1-refTmp)*dfTmp$poolxpert)
tn<-sum(na.rm=TRUE,(1-refTmp)*(1-dfTmp$poolxpert))
fn<-sum(na.rm=TRUE,refTmp*(1-dfTmp$poolxpert))
dfPerf$poolxpert_sens[j]<-paste(sep="",format(nsmall=1,round(digits=1,100*tp/(tp+fn))),"% (",tp,"/",tp+fn,")")
dfPerf$poolxpert_spec[j]<-paste(sep="",format(nsmall=1,round(digits=1,100*tn/(tn+fp))),"% (",tn,"/",tn+fp,")")
#XPERT SINGLE
tp<-sum(na.rm=TRUE,refTmp*dfTmp$xpert)
fp<-sum(na.rm=TRUE,(1-refTmp)*dfTmp$xpert)
tn<-sum(na.rm=TRUE,(1-refTmp)*(1-dfTmp$xpert))
fn<-sum(na.rm=TRUE,refTmp*(1-dfTmp$xpert))
dfPerf$xpert_sens[j]<-paste(sep="",format(nsmall=1,round(digits=1,100*tp/(tp+fn))),"% (",tp,"/",tp+fn,")")
dfPerf$xpert_spec[j]<-paste(sep="",format(nsmall=1,round(digits=1,100*tn/(tn+fp))),"% (",tn,"/",tn+fp,")")
rm(list=c("dfTmp","tp","tn","fp","fn"))
}
dfPerf$CRS<-gsub(dfPerf$CRS,pattern="_+",replacement=" ")
dfPerf<-dfPerf[!grepl(pattern="NaN",dfPerf$Prevalence),]
dfPerf<-dfPerf[dfPerf$cultNegXpertNeg+dfPerf$cultPosXpertNeg+dfPerf$cultNegXpertPos+dfPerf$cultPosXpertPos>=5,]
for(i in 1:nrow(dfPerf)){
for(j in 1:ncol(dfPerf)){
if(grepl(pattern="NaN",dfPerf[i,j])){dfPerf[i,j]<-NA}
}
}
dfPerf %>%
dplyr::select(!c(Country,Region,Setting,CRS)) %>%
kable(row.names = FALSE,col.names=c("Reference","Population","TB prevalence","-/-","+/-","-/+","+/+",rep(c("sensitivity","specifity"),6))) %>%
add_header_above(c(" "=1," "=1," "=1,"Culture/Xpert"=4,"CXR"=2,"CRP"=2,"LAM"=2,"SSM"=2,"Pooled Xpert"=2,"Xpert Ultra"=2)) %>%
kableExtra::group_rows(index=table(fct_inorder(dfPerf$CRS))) %>%
kable_styling(full_width=FALSE)| Reference | Population | TB prevalence | -/- | +/- | -/+ | +/+ | sensitivity | specifity | sensitivity | specifity | sensitivity | specifity | sensitivity | specifity | sensitivity | specifity | sensitivity | specifity |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Cameroon PHC | ||||||||||||||||||
| culture | All | 7.9% (79/1000) | 916 | 1 | 5 | 78 | 86.1% (68/79) | 86.4% (796/921) | 84.8% (67/79) | 94.2% (868/921) | 82.3% (65/79) | 89.0% (820/921) | 65.8% (52/79) | 96.2% (886/921) | 93.7% (74/79) | 95.0% (875/921) | 98.7% (78/79) | 99.5% (916/921) |
| xpert | All | 8.3% (83/1000) | 916 | 1 | 5 | 78 | 81.9% (68/83) | 86.4% (792/917) | 80.7% (67/83) | 94.2% (864/917) | 78.3% (65/83) | 89.0% (816/917) | 61.4% (51/83) | 96.1% (881/917) | 90.4% (75/83) | 95.1% (872/917) | 100.0% (83/83) | 100.0% (917/917) |
| culture | PLWithHIV | 11.6% (50/431) | 380 | 1 | 1 | 49 | 88.0% (44/50) | 85.0% (324/381) | 84.0% (42/50) | 92.1% (351/381) | 84.0% (42/50) | 88.7% (338/381) | 68.0% (34/50) | 95.8% (365/381) | 90.0% (45/50) | 96.3% (367/381) | 98.0% (49/50) | 99.7% (380/381) |
| xpert | PLWithHIV | 11.6% (50/431) | 380 | 1 | 1 | 49 | 88.0% (44/50) | 85.0% (324/381) | 82.0% (41/50) | 91.9% (350/381) | 84.0% (42/50) | 88.7% (338/381) | 66.0% (33/50) | 95.5% (364/381) | 90.0% (45/50) | 96.3% (367/381) | 100.0% (50/50) | 100.0% (381/381) |
| culture | PLWithoutHIV | 5.1% (29/569) | 536 | 0 | 4 | 29 | 82.8% (24/29) | 87.4% (472/540) | 86.2% (25/29) | 95.7% (517/540) | 79.3% (23/29) | 89.3% (482/540) | 62.1% (18/29) | 96.5% (521/540) | 100.0% (29/29) | 94.1% (508/540) | 100.0% (29/29) | 99.3% (536/540) |
| xpert | PLWithoutHIV | 5.8% (33/569) | 536 | 0 | 4 | 29 | 72.7% (24/33) | 87.3% (468/536) | 78.8% (26/33) | 95.9% (514/536) | 69.7% (23/33) | 89.2% (478/536) | 54.5% (18/33) | 96.5% (517/536) | 90.9% (30/33) | 94.2% (505/536) | 100.0% (33/33) | 100.0% (536/536) |
| Cameroon District | ||||||||||||||||||
| culture | All | 8.5% (85/1000) | 907 | 3 | 8 | 82 | 85.9% (73/85) | 88.3% (808/915) | 92.9% (79/85) | 94.6% (866/915) | 81.2% (69/85) | 88.4% (809/915) | 69.4% (59/85) | 96.7% (885/915) | 90.6% (77/85) | 95.4% (873/915) | 96.5% (82/85) | 99.1% (907/915) |
| xpert | All | 9.0% (90/1000) | 907 | 3 | 8 | 82 | 78.9% (71/90) | 88.0% (801/910) | 84.4% (76/90) | 94.3% (858/910) | 75.6% (68/90) | 88.2% (803/910) | 64.4% (58/90) | 96.6% (879/910) | 82.2% (74/90) | 95.1% (865/910) | 100.0% (90/90) | 100.0% (910/910) |
| culture | PLWithHIV | 14.2% (63/445) | 380 | 3 | 2 | 60 | 84.1% (53/63) | 88.0% (336/382) | 93.7% (59/63) | 95.3% (364/382) | 82.5% (52/63) | 87.4% (334/382) | 68.3% (43/63) | 96.9% (370/382) | 88.9% (56/63) | 95.0% (363/382) | 95.2% (60/63) | 99.5% (380/382) |
| xpert | PLWithHIV | 13.9% (62/445) | 380 | 3 | 2 | 60 | 80.6% (50/62) | 87.2% (334/383) | 90.3% (56/62) | 94.5% (362/383) | 79.0% (49/62) | 86.7% (332/383) | 67.7% (42/62) | 96.6% (370/383) | 85.5% (53/62) | 94.3% (361/383) | 100.0% (62/62) | 100.0% (383/383) |
| culture | PLWithoutHIV | 4.0% (22/555) | 527 | 0 | 6 | 22 | 90.9% (20/22) | 88.6% (472/533) | 90.9% (20/22) | 94.2% (502/533) | 77.3% (17/22) | 89.1% (475/533) | 72.7% (16/22) | 96.6% (515/533) | 95.5% (21/22) | 95.7% (510/533) | 100.0% (22/22) | 98.9% (527/533) |
| xpert | PLWithoutHIV | 5.0% (28/555) | 527 | 0 | 6 | 22 | 75.0% (21/28) | 88.6% (467/527) | 71.4% (20/28) | 94.1% (496/527) | 67.9% (19/28) | 89.4% (471/527) | 57.1% (16/28) | 96.6% (509/527) | 75.0% (21/28) | 95.6% (504/527) | 100.0% (28/28) | 100.0% (527/527) |
| Cameroon Nomads | ||||||||||||||||||
| culture | All | 3.8% (30/800) | 763 | 1 | 7 | 29 | 93.3% (28/30) | 86.4% (665/770) | 83.3% (25/30) | 95.7% (737/770) | 80.0% (24/30) | 88.7% (683/770) | 63.3% (19/30) | 95.8% (738/770) | 96.7% (29/30) | 95.8% (738/770) | 96.7% (29/30) | 99.1% (763/770) |
| xpert | All | 4.5% (36/800) | 763 | 1 | 7 | 29 | 83.3% (30/36) | 86.5% (661/764) | 66.7% (24/36) | 95.5% (730/764) | 66.7% (24/36) | 88.6% (677/764) | 50.0% (18/36) | 95.7% (731/764) | 80.6% (29/36) | 95.8% (732/764) | 100.0% (36/36) | 100.0% (764/764) |
| culture | PLWithHIV | 6.4% (21/328) | 304 | 0 | 3 | 21 | 95.2% (20/21) | 86.6% (266/307) | 81.0% (17/21) | 94.8% (291/307) | 76.2% (16/21) | 87.0% (267/307) | 61.9% (13/21) | 95.1% (292/307) | 100.0% (21/21) | 96.1% (295/307) | 100.0% (21/21) | 99.0% (304/307) |
| xpert | PLWithHIV | 7.3% (24/328) | 304 | 0 | 3 | 21 | 87.5% (21/24) | 86.8% (264/304) | 70.8% (17/24) | 94.7% (288/304) | 70.8% (17/24) | 87.2% (265/304) | 54.2% (13/24) | 95.1% (289/304) | 87.5% (21/24) | 96.1% (292/304) | 100.0% (24/24) | 100.0% (304/304) |
| culture | PLWithoutHIV | 1.9% (9/472) | 459 | 1 | 4 | 8 | 88.9% (8/9) | 86.2% (399/463) | 88.9% (8/9) | 96.3% (446/463) | 88.9% (8/9) | 89.8% (416/463) | 66.7% (6/9) | 96.3% (446/463) | 88.9% (8/9) | 95.7% (443/463) | 88.9% (8/9) | 99.1% (459/463) |
| xpert | PLWithoutHIV | 2.5% (12/472) | 459 | 1 | 4 | 8 | 75.0% (9/12) | 86.3% (397/460) | 58.3% (7/12) | 96.1% (442/460) | 58.3% (7/12) | 89.6% (412/460) | 41.7% (5/12) | 96.1% (442/460) | 66.7% (8/12) | 95.7% (440/460) | 100.0% (12/12) | 100.0% (460/460) |
| Cameroon Children | ||||||||||||||||||
| culture | All | 3.4% (17/500) | 480 | 0 | 3 | 17 | 88.2% (15/17) | 85.7% (414/483) | 76.5% (13/17) | 96.1% (464/483) | 88.2% (15/17) | 89.6% (433/483) | 64.7% (11/17) | 95.7% (462/483) | 94.1% (16/17) | 97.1% (469/483) | 100.0% (17/17) | 99.4% (480/483) |
| xpert | All | 4.0% (20/500) | 480 | 0 | 3 | 17 | 75.0% (15/20) | 85.6% (411/480) | 70.0% (14/20) | 96.2% (462/480) | 75.0% (15/20) | 89.6% (430/480) | 55.0% (11/20) | 95.6% (459/480) | 80.0% (16/20) | 97.1% (466/480) | 100.0% (20/20) | 100.0% (480/480) |
| culture | PLWithHIV | 4.3% (9/210) | 200 | 0 | 1 | 9 | 77.8% (7/9) | 87.6% (176/201) | 88.9% (8/9) | 95.5% (192/201) | 77.8% (7/9) | 91.0% (183/201) | 66.7% (6/9) | 95.5% (192/201) | 88.9% (8/9) | 97.5% (196/201) | 100.0% (9/9) | 99.5% (200/201) |
| xpert | PLWithHIV | 4.8% (10/210) | 200 | 0 | 1 | 9 | 70.0% (7/10) | 87.5% (175/200) | 80.0% (8/10) | 95.5% (191/200) | 70.0% (7/10) | 91.0% (182/200) | 60.0% (6/10) | 95.5% (191/200) | 80.0% (8/10) | 97.5% (195/200) | 100.0% (10/10) | 100.0% (200/200) |
| culture | PLWithoutHIV | 2.8% (8/290) | 280 | 0 | 2 | 8 | 100.0% (8/8) | 84.4% (238/282) | 62.5% (5/8) | 96.5% (272/282) | 100.0% (8/8) | 88.7% (250/282) | 62.5% (5/8) | 95.7% (270/282) | 100.0% (8/8) | 96.8% (273/282) | 100.0% (8/8) | 99.3% (280/282) |
| xpert | PLWithoutHIV | 3.4% (10/290) | 280 | 0 | 2 | 8 | 80.0% (8/10) | 84.3% (236/280) | 60.0% (6/10) | 96.8% (271/280) | 80.0% (8/10) | 88.6% (248/280) | 50.0% (5/10) | 95.7% (268/280) | 80.0% (8/10) | 96.8% (271/280) | 100.0% (10/10) | 100.0% (280/280) |
| Nigeria ZRC PHC | ||||||||||||||||||
| culture | All | 21.9% (153/700) | 540 | 5 | 7 | 148 | 88.9% (136/153) | 88.3% (483/547) | 96.1% (147/153) | 96.9% (530/547) | 81.0% (124/153) | 88.7% (485/547) | 68.6% (105/153) | 95.6% (523/547) | 92.2% (141/153) | 98.4% (538/547) | 96.7% (148/153) | 98.7% (540/547) |
| xpert | All | 22.1% (155/700) | 540 | 5 | 7 | 148 | 85.8% (133/155) | 87.7% (478/545) | 92.3% (143/155) | 96.1% (524/545) | 77.4% (120/155) | 87.9% (479/545) | 65.8% (102/155) | 95.0% (518/545) | 89.0% (138/155) | 97.8% (533/545) | 100.0% (155/155) | 100.0% (545/545) |
| culture | PLWithHIV | 34.3% (113/329) | 215 | 3 | 1 | 110 | 89.4% (101/113) | 88.9% (192/216) | 96.5% (109/113) | 97.7% (211/216) | 79.6% (90/113) | 90.7% (196/216) | 69.9% (79/113) | 95.8% (207/216) | 92.9% (105/113) | 99.1% (214/216) | 97.3% (110/113) | 99.5% (215/216) |
| xpert | PLWithHIV | 33.7% (111/329) | 215 | 3 | 1 | 110 | 89.2% (99/111) | 88.1% (192/218) | 95.5% (106/111) | 96.3% (210/218) | 78.4% (87/111) | 89.4% (195/218) | 69.4% (77/111) | 95.0% (207/218) | 92.8% (103/111) | 98.2% (214/218) | 100.0% (111/111) | 100.0% (218/218) |
| culture | PLWithoutHIV | 10.8% (40/371) | 325 | 2 | 6 | 38 | 87.5% (35/40) | 87.9% (291/331) | 95.0% (38/40) | 96.4% (319/331) | 85.0% (34/40) | 87.3% (289/331) | 65.0% (26/40) | 95.5% (316/331) | 90.0% (36/40) | 97.9% (324/331) | 95.0% (38/40) | 98.2% (325/331) |
| xpert | PLWithoutHIV | 11.9% (44/371) | 325 | 2 | 6 | 38 | 77.3% (34/44) | 87.5% (286/327) | 84.1% (37/44) | 96.0% (314/327) | 75.0% (33/44) | 86.9% (284/327) | 56.8% (25/44) | 95.1% (311/327) | 79.5% (35/44) | 97.6% (319/327) | 100.0% (44/44) | 100.0% (327/327) |
| Nigeria ZRC District | ||||||||||||||||||
| culture | All | 17.0% (119/700) | 576 | 2 | 5 | 117 | 91.6% (109/119) | 86.1% (500/581) | 92.4% (110/119) | 93.1% (541/581) | 79.0% (94/119) | 88.6% (515/581) | 64.7% (77/119) | 95.5% (555/581) | 90.8% (108/119) | 97.2% (565/581) | 98.3% (117/119) | 99.1% (576/581) |
| xpert | All | 17.4% (122/700) | 576 | 2 | 5 | 117 | 89.3% (109/122) | 86.0% (497/578) | 88.5% (108/122) | 92.7% (536/578) | 76.2% (93/122) | 88.4% (511/578) | 63.1% (77/122) | 95.5% (552/578) | 86.9% (106/122) | 96.9% (560/578) | 100.0% (122/122) | 100.0% (578/578) |
| culture | PLWithHIV | 22.5% (73/324) | 251 | 2 | 0 | 71 | 94.5% (69/73) | 86.5% (217/251) | 90.4% (66/73) | 94.4% (237/251) | 76.7% (56/73) | 90.0% (226/251) | 60.3% (44/73) | 94.4% (237/251) | 90.4% (66/73) | 98.4% (247/251) | 97.3% (71/73) | 100.0% (251/251) |
| xpert | PLWithHIV | 21.9% (71/324) | 251 | 2 | 0 | 71 | 94.4% (67/71) | 85.8% (217/253) | 90.1% (64/71) | 93.7% (237/253) | 76.1% (54/71) | 89.3% (226/253) | 62.0% (44/71) | 94.5% (239/253) | 90.1% (64/71) | 97.6% (247/253) | 100.0% (71/71) | 100.0% (253/253) |
| culture | PLWithoutHIV | 12.2% (46/376) | 325 | 0 | 5 | 46 | 87.0% (40/46) | 85.8% (283/330) | 95.7% (44/46) | 92.1% (304/330) | 82.6% (38/46) | 87.6% (289/330) | 71.7% (33/46) | 96.4% (318/330) | 91.3% (42/46) | 96.4% (318/330) | 100.0% (46/46) | 98.5% (325/330) |
| xpert | PLWithoutHIV | 13.6% (51/376) | 325 | 0 | 5 | 46 | 82.4% (42/51) | 86.2% (280/325) | 86.3% (44/51) | 92.0% (299/325) | 76.5% (39/51) | 87.7% (285/325) | 64.7% (33/51) | 96.3% (313/325) | 82.4% (42/51) | 96.3% (313/325) | 100.0% (51/51) | 100.0% (325/325) |
| Nigeria JHF Nomads | ||||||||||||||||||
| culture | All | 7.7% (77/1000) | 909 | 1 | 14 | 76 | 89.6% (69/77) | 88.4% (816/923) | 94.8% (73/77) | 96.3% (889/923) | 85.7% (66/77) | 88.1% (813/923) | 72.7% (56/77) | 95.2% (879/923) | 88.3% (68/77) | 97.0% (895/923) | 98.7% (76/77) | 98.5% (909/923) |
| xpert | All | 9.0% (90/1000) | 909 | 1 | 14 | 76 | 80.0% (72/90) | 88.6% (806/910) | 80.0% (72/90) | 96.2% (875/910) | 72.2% (65/90) | 87.8% (799/910) | 63.3% (57/90) | 95.3% (867/910) | 75.6% (68/90) | 96.9% (882/910) | 100.0% (90/90) | 100.0% (910/910) |
| culture | PLWithHIV | 11.3% (49/432) | 378 | 1 | 5 | 48 | 89.8% (44/49) | 88.3% (338/383) | 95.9% (47/49) | 96.1% (368/383) | 87.8% (43/49) | 86.4% (331/383) | 71.4% (35/49) | 95.6% (366/383) | 83.7% (41/49) | 95.0% (364/383) | 98.0% (48/49) | 98.7% (378/383) |
| xpert | PLWithHIV | 12.3% (53/432) | 378 | 1 | 5 | 48 | 84.9% (45/53) | 88.4% (335/379) | 86.8% (46/53) | 95.8% (363/379) | 79.2% (42/53) | 86.0% (326/379) | 66.0% (35/53) | 95.5% (362/379) | 77.4% (41/53) | 95.0% (360/379) | 100.0% (53/53) | 100.0% (379/379) |
| culture | PLWithoutHIV | 4.9% (28/568) | 531 | 0 | 9 | 28 | 89.3% (25/28) | 88.5% (478/540) | 92.9% (26/28) | 96.5% (521/540) | 82.1% (23/28) | 89.3% (482/540) | 75.0% (21/28) | 95.0% (513/540) | 96.4% (27/28) | 98.3% (531/540) | 100.0% (28/28) | 98.3% (531/540) |
| xpert | PLWithoutHIV | 6.5% (37/568) | 531 | 0 | 9 | 28 | 73.0% (27/37) | 88.7% (471/531) | 70.3% (26/37) | 96.4% (512/531) | 62.2% (23/37) | 89.1% (473/531) | 59.5% (22/37) | 95.1% (505/531) | 73.0% (27/37) | 98.3% (522/531) | 100.0% (37/37) | 100.0% (531/531) |
| Nigeria JHF IDP / refugees | ||||||||||||||||||
| culture | All | 11.7% (117/1000) | 875 | 2 | 8 | 115 | 87.2% (102/117) | 89.7% (792/883) | 92.3% (108/117) | 94.5% (834/883) | 82.1% (96/117) | 88.6% (782/883) | 82.9% (97/117) | 96.5% (852/883) | 86.3% (101/117) | 98.0% (865/883) | 98.3% (115/117) | 99.1% (875/883) |
| xpert | All | 12.3% (123/1000) | 875 | 2 | 8 | 115 | 81.3% (100/123) | 89.4% (784/877) | 86.2% (106/123) | 94.2% (826/877) | 77.2% (95/123) | 88.4% (775/877) | 77.2% (95/123) | 96.2% (844/877) | 81.3% (100/123) | 97.8% (858/877) | 100.0% (123/123) | 100.0% (877/877) |
| culture | PLWithHIV | 18.0% (77/427) | 348 | 2 | 2 | 75 | 85.7% (66/77) | 88.6% (310/350) | 90.9% (70/77) | 93.7% (328/350) | 80.5% (62/77) | 89.7% (314/350) | 84.4% (65/77) | 96.3% (337/350) | 87.0% (67/77) | 98.0% (343/350) | 97.4% (75/77) | 99.4% (348/350) |
| xpert | PLWithHIV | 18.0% (77/427) | 348 | 2 | 2 | 75 | 83.1% (64/77) | 88.0% (308/350) | 88.3% (68/77) | 93.1% (326/350) | 77.9% (60/77) | 89.1% (312/350) | 81.8% (63/77) | 95.7% (335/350) | 84.4% (65/77) | 97.4% (341/350) | 100.0% (77/77) | 100.0% (350/350) |
| culture | PLWithoutHIV | 7.0% (40/573) | 527 | 0 | 6 | 40 | 90.0% (36/40) | 90.4% (482/533) | 95.0% (38/40) | 94.9% (506/533) | 85.0% (34/40) | 87.8% (468/533) | 80.0% (32/40) | 96.6% (515/533) | 85.0% (34/40) | 97.9% (522/533) | 100.0% (40/40) | 98.9% (527/533) |
| xpert | PLWithoutHIV | 8.0% (46/573) | 527 | 0 | 6 | 40 | 78.3% (36/46) | 90.3% (476/527) | 82.6% (38/46) | 94.9% (500/527) | 76.1% (35/46) | 87.9% (463/527) | 69.6% (32/46) | 96.6% (509/527) | 76.1% (35/46) | 98.1% (517/527) | 100.0% (46/46) | 100.0% (527/527) |
| Kenya PHC | ||||||||||||||||||
| culture | All | 8.4% (59/700) | 633 | 0 | 8 | 59 | 79.7% (47/59) | 87.8% (563/641) | 89.8% (53/59) | 94.5% (606/641) | 81.4% (48/59) | 87.8% (563/641) | 69.5% (41/59) | 96.1% (616/641) | 91.5% (54/59) | 97.0% (622/641) | 100.0% (59/59) | 98.8% (633/641) |
| xpert | All | 9.6% (67/700) | 633 | 0 | 8 | 59 | 70.1% (47/67) | 87.7% (555/633) | 82.1% (55/67) | 94.8% (600/633) | 74.6% (50/67) | 88.0% (557/633) | 61.2% (41/67) | 96.1% (608/633) | 82.1% (55/67) | 97.2% (615/633) | 100.0% (67/67) | 100.0% (633/633) |
| culture | PLWithHIV | 12.1% (38/315) | 275 | 0 | 2 | 38 | 73.7% (28/38) | 91.0% (252/277) | 86.8% (33/38) | 94.2% (261/277) | 78.9% (30/38) | 87.7% (243/277) | 60.5% (23/38) | 96.0% (266/277) | 89.5% (34/38) | 97.8% (271/277) | 100.0% (38/38) | 99.3% (275/277) |
| xpert | PLWithHIV | 12.7% (40/315) | 275 | 0 | 2 | 38 | 70.0% (28/40) | 90.9% (250/275) | 85.0% (34/40) | 94.5% (260/275) | 77.5% (31/40) | 88.0% (242/275) | 57.5% (23/40) | 96.0% (264/275) | 85.0% (34/40) | 97.8% (269/275) | 100.0% (40/40) | 100.0% (275/275) |
| culture | PLWithoutHIV | 5.5% (21/385) | 358 | 0 | 6 | 21 | 90.5% (19/21) | 85.4% (311/364) | 95.2% (20/21) | 94.8% (345/364) | 85.7% (18/21) | 87.9% (320/364) | 85.7% (18/21) | 96.2% (350/364) | 95.2% (20/21) | 96.4% (351/364) | 100.0% (21/21) | 98.4% (358/364) |
| xpert | PLWithoutHIV | 7.0% (27/385) | 358 | 0 | 6 | 21 | 70.4% (19/27) | 85.2% (305/358) | 77.8% (21/27) | 95.0% (340/358) | 70.4% (19/27) | 88.0% (315/358) | 66.7% (18/27) | 96.1% (344/358) | 77.8% (21/27) | 96.6% (346/358) | 100.0% (27/27) | 100.0% (358/358) |
| Kenya District | ||||||||||||||||||
| culture | All | 19.7% (138/700) | 550 | 3 | 12 | 135 | 93.5% (129/138) | 87.5% (492/562) | 87.7% (121/138) | 96.6% (543/562) | 81.2% (112/138) | 88.3% (496/562) | 72.5% (100/138) | 95.2% (535/562) | 91.3% (126/138) | 95.7% (538/562) | 97.8% (135/138) | 97.9% (550/562) |
| xpert | All | 21.0% (147/700) | 550 | 3 | 12 | 135 | 86.4% (127/147) | 87.0% (481/553) | 81.0% (119/147) | 96.2% (532/553) | 74.8% (110/147) | 87.7% (485/553) | 66.0% (97/147) | 94.6% (523/553) | 84.4% (124/147) | 95.3% (527/553) | 100.0% (147/147) | 100.0% (553/553) |
| culture | PLWithHIV | 30.0% (99/330) | 226 | 2 | 5 | 97 | 91.9% (91/99) | 86.1% (199/231) | 87.9% (87/99) | 97.0% (224/231) | 78.8% (78/99) | 87.4% (202/231) | 69.7% (69/99) | 93.9% (217/231) | 89.9% (89/99) | 96.5% (223/231) | 98.0% (97/99) | 97.8% (226/231) |
| xpert | PLWithHIV | 30.9% (102/330) | 226 | 2 | 5 | 97 | 88.2% (90/102) | 85.5% (195/228) | 84.3% (86/102) | 96.5% (220/228) | 74.5% (76/102) | 86.4% (197/228) | 65.7% (67/102) | 93.0% (212/228) | 85.3% (87/102) | 95.6% (218/228) | 100.0% (102/102) | 100.0% (228/228) |
| culture | PLWithoutHIV | 10.5% (39/370) | 324 | 1 | 7 | 38 | 97.4% (38/39) | 88.5% (293/331) | 87.2% (34/39) | 96.4% (319/331) | 87.2% (34/39) | 88.8% (294/331) | 79.5% (31/39) | 96.1% (318/331) | 94.9% (37/39) | 95.2% (315/331) | 97.4% (38/39) | 97.9% (324/331) |
| xpert | PLWithoutHIV | 12.2% (45/370) | 324 | 1 | 7 | 38 | 82.2% (37/45) | 88.0% (286/325) | 73.3% (33/45) | 96.0% (312/325) | 75.6% (34/45) | 88.6% (288/325) | 66.7% (30/45) | 95.7% (311/325) | 82.2% (37/45) | 95.1% (309/325) | 100.0% (45/45) | 100.0% (325/325) |
| Bangladesh PHC | ||||||||||||||||||
| culture | All | 3.4% (34/1000) | 954 | 0 | 12 | 34 | 97.1% (33/34) | 89.8% (867/966) | 88.2% (30/34) | 95.2% (920/966) | 82.4% (28/34) | 91.7% (886/966) | 76.5% (26/34) | 93.4% (902/966) | 85.3% (29/34) | 96.8% (935/966) | 100.0% (34/34) | 98.8% (954/966) |
| xpert | All | 4.6% (46/1000) | 954 | 0 | 12 | 34 | 73.9% (34/46) | 89.7% (856/954) | 65.2% (30/46) | 95.2% (908/954) | 60.9% (28/46) | 91.6% (874/954) | 58.7% (27/46) | 93.4% (891/954) | 63.0% (29/46) | 96.8% (923/954) | 100.0% (46/46) | 100.0% (954/954) |
| culture | PLWithHIV | 6.6% (26/391) | 360 | 0 | 5 | 26 | 96.2% (25/26) | 88.8% (324/365) | 84.6% (22/26) | 94.0% (343/365) | 76.9% (20/26) | 92.3% (337/365) | 73.1% (19/26) | 92.3% (337/365) | 88.5% (23/26) | 97.0% (354/365) | 100.0% (26/26) | 98.6% (360/365) |
| xpert | PLWithHIV | 7.9% (31/391) | 360 | 0 | 5 | 26 | 80.6% (25/31) | 88.6% (319/360) | 71.0% (22/31) | 93.9% (338/360) | 64.5% (20/31) | 92.2% (332/360) | 61.3% (19/31) | 92.2% (332/360) | 74.2% (23/31) | 96.9% (349/360) | 100.0% (31/31) | 100.0% (360/360) |
| culture | PLWithoutHIV | 1.3% (8/609) | 594 | 0 | 7 | 8 | 100.0% (8/8) | 90.3% (543/601) | 100.0% (8/8) | 96.0% (577/601) | 100.0% (8/8) | 91.3% (549/601) | 87.5% (7/8) | 94.0% (565/601) | 75.0% (6/8) | 96.7% (581/601) | 100.0% (8/8) | 98.8% (594/601) |
| xpert | PLWithoutHIV | 2.5% (15/609) | 594 | 0 | 7 | 8 | 60.0% (9/15) | 90.4% (537/594) | 53.3% (8/15) | 96.0% (570/594) | 53.3% (8/15) | 91.2% (542/594) | 53.3% (8/15) | 94.1% (559/594) | 40.0% (6/15) | 96.6% (574/594) | 100.0% (15/15) | 100.0% (594/594) |
| Bangladesh District | ||||||||||||||||||
| culture | All | 2.5% (25/1000) | 961 | 0 | 14 | 25 | 84.0% (21/25) | 92.0% (897/975) | 88.0% (22/25) | 95.5% (931/975) | 92.0% (23/25) | 89.6% (874/975) | 64.0% (16/25) | 94.4% (920/975) | 84.0% (21/25) | 97.1% (947/975) | 100.0% (25/25) | 98.6% (961/975) |
| xpert | All | 3.9% (39/1000) | 961 | 0 | 14 | 25 | 56.4% (22/39) | 92.0% (884/961) | 59.0% (23/39) | 95.5% (918/961) | 59.0% (23/39) | 89.5% (860/961) | 41.0% (16/39) | 94.3% (906/961) | 56.4% (22/39) | 97.2% (934/961) | 100.0% (39/39) | 100.0% (961/961) |
| culture | PLWithHIV | 4.3% (17/399) | 375 | 0 | 7 | 17 | 82.4% (14/17) | 91.1% (348/382) | 88.2% (15/17) | 95.0% (363/382) | 94.1% (16/17) | 92.1% (352/382) | 70.6% (12/17) | 95.3% (364/382) | 76.5% (13/17) | 97.6% (373/382) | 100.0% (17/17) | 98.2% (375/382) |
| xpert | PLWithHIV | 6.0% (24/399) | 375 | 0 | 7 | 17 | 62.5% (15/24) | 91.2% (342/375) | 66.7% (16/24) | 95.2% (357/375) | 66.7% (16/24) | 92.0% (345/375) | 50.0% (12/24) | 95.2% (357/375) | 54.2% (13/24) | 97.6% (366/375) | 100.0% (24/24) | 100.0% (375/375) |
| culture | PLWithoutHIV | 1.3% (8/601) | 586 | 0 | 7 | 8 | 87.5% (7/8) | 92.6% (549/593) | 87.5% (7/8) | 95.8% (568/593) | 87.5% (7/8) | 88.0% (522/593) | 50.0% (4/8) | 93.8% (556/593) | 100.0% (8/8) | 96.8% (574/593) | 100.0% (8/8) | 98.8% (586/593) |
| xpert | PLWithoutHIV | 2.5% (15/601) | 586 | 0 | 7 | 8 | 46.7% (7/15) | 92.5% (542/586) | 46.7% (7/15) | 95.7% (561/586) | 46.7% (7/15) | 87.9% (515/586) | 26.7% (4/15) | 93.7% (549/586) | 60.0% (9/15) | 96.9% (568/586) | 100.0% (15/15) | 100.0% (586/586) |
| Bangladesh Informal settlements | ||||||||||||||||||
| culture | All | 4.9% (49/1000) | 940 | 1 | 11 | 48 | 85.7% (42/49) | 91.4% (869/951) | 77.6% (38/49) | 95.4% (907/951) | 81.6% (40/49) | 92.3% (878/951) | 75.5% (37/49) | 94.0% (894/951) | 89.8% (44/49) | 96.2% (915/951) | 98.0% (48/49) | 98.8% (940/951) |
| xpert | All | 5.9% (59/1000) | 940 | 1 | 11 | 48 | 71.2% (42/59) | 91.3% (859/941) | 66.1% (39/59) | 95.4% (898/941) | 69.5% (41/59) | 92.3% (869/941) | 66.1% (39/59) | 94.2% (886/941) | 72.9% (43/59) | 96.1% (904/941) | 100.0% (59/59) | 100.0% (941/941) |
| culture | PLWithHIV | 8.6% (36/419) | 379 | 0 | 4 | 36 | 88.9% (32/36) | 92.4% (354/383) | 75.0% (27/36) | 94.5% (362/383) | 83.3% (30/36) | 93.7% (359/383) | 83.3% (30/36) | 93.2% (357/383) | 97.2% (35/36) | 96.1% (368/383) | 100.0% (36/36) | 99.0% (379/383) |
| xpert | PLWithHIV | 9.5% (40/419) | 379 | 0 | 4 | 36 | 82.5% (33/40) | 92.6% (351/379) | 70.0% (28/40) | 94.7% (359/379) | 77.5% (31/40) | 93.9% (356/379) | 75.0% (30/40) | 93.1% (353/379) | 87.5% (35/40) | 96.0% (364/379) | 100.0% (40/40) | 100.0% (379/379) |
| culture | PLWithoutHIV | 2.2% (13/581) | 561 | 1 | 7 | 12 | 76.9% (10/13) | 90.7% (515/568) | 84.6% (11/13) | 96.0% (545/568) | 76.9% (10/13) | 91.4% (519/568) | 53.8% (7/13) | 94.5% (537/568) | 69.2% (9/13) | 96.3% (547/568) | 92.3% (12/13) | 98.8% (561/568) |
| xpert | PLWithoutHIV | 3.3% (19/581) | 561 | 1 | 7 | 12 | 47.4% (9/19) | 90.4% (508/562) | 57.9% (11/19) | 95.9% (539/562) | 52.6% (10/19) | 91.3% (513/562) | 47.4% (9/19) | 94.8% (533/562) | 42.1% (8/19) | 96.1% (540/562) | 100.0% (19/19) | 100.0% (562/562) |
| Brazil Aracaju PHC | ||||||||||||||||||
| culture | All | 14.8% (74/500) | 425 | 2 | 1 | 72 | 93.2% (69/74) | 84.3% (359/426) | 82.4% (61/74) | 97.9% (417/426) | 83.8% (62/74) | 91.1% (388/426) | 66.2% (49/74) | 95.5% (407/426) | 91.9% (68/74) | 97.7% (416/426) | 97.3% (72/74) | 99.8% (425/426) |
| xpert | All | 14.6% (73/500) | 425 | 2 | 1 | 72 | 91.8% (67/73) | 83.8% (358/427) | 83.6% (61/73) | 97.9% (418/427) | 83.6% (61/73) | 90.9% (388/427) | 65.8% (48/73) | 95.3% (407/427) | 91.8% (67/73) | 97.4% (416/427) | 100.0% (73/73) | 100.0% (427/427) |
| culture | PLWithHIV | 21.8% (48/220) | 171 | 2 | 1 | 46 | 89.6% (43/48) | 83.7% (144/172) | 77.1% (37/48) | 97.7% (168/172) | 85.4% (41/48) | 91.9% (158/172) | 64.6% (31/48) | 95.3% (164/172) | 91.7% (44/48) | 97.7% (168/172) | 95.8% (46/48) | 99.4% (171/172) |
| xpert | PLWithHIV | 21.4% (47/220) | 171 | 2 | 1 | 46 | 87.2% (41/47) | 82.7% (143/173) | 78.7% (37/47) | 97.7% (169/173) | 85.1% (40/47) | 91.3% (158/173) | 63.8% (30/47) | 94.8% (164/173) | 91.5% (43/47) | 97.1% (168/173) | 100.0% (47/47) | 100.0% (173/173) |
| culture | PLWithoutHIV | 9.3% (26/280) | 254 | 0 | 0 | 26 | 100.0% (26/26) | 84.6% (215/254) | 92.3% (24/26) | 98.0% (249/254) | 80.8% (21/26) | 90.6% (230/254) | 69.2% (18/26) | 95.7% (243/254) | 92.3% (24/26) | 97.6% (248/254) | 100.0% (26/26) | 100.0% (254/254) |
| xpert | PLWithoutHIV | 9.3% (26/280) | 254 | 0 | 0 | 26 | 100.0% (26/26) | 84.6% (215/254) | 92.3% (24/26) | 98.0% (249/254) | 80.8% (21/26) | 90.6% (230/254) | 69.2% (18/26) | 95.7% (243/254) | 92.3% (24/26) | 97.6% (248/254) | 100.0% (26/26) | 100.0% (254/254) |
| Brazil Maceio PHC | ||||||||||||||||||
| culture | All | 28.2% (141/500) | 357 | 1 | 2 | 140 | 85.8% (121/141) | 90.5% (325/359) | 86.5% (122/141) | 96.7% (347/359) | 77.3% (109/141) | 88.6% (318/359) | 63.1% (89/141) | 93.9% (337/359) | 92.2% (130/141) | 97.5% (350/359) | 99.3% (140/141) | 99.4% (357/359) |
| xpert | All | 28.4% (142/500) | 357 | 1 | 2 | 140 | 84.5% (120/142) | 90.2% (323/358) | 85.9% (122/142) | 96.6% (346/358) | 76.1% (108/142) | 88.3% (316/358) | 62.0% (88/142) | 93.6% (335/358) | 90.8% (129/142) | 97.2% (348/358) | 100.0% (142/142) | 100.0% (358/358) |
| culture | PLWithHIV | 44.2% (103/233) | 129 | 1 | 1 | 102 | 84.5% (87/103) | 90.0% (117/130) | 88.3% (91/103) | 96.2% (125/130) | 75.7% (78/103) | 89.2% (116/130) | 65.0% (67/103) | 96.2% (125/130) | 94.2% (97/103) | 99.2% (129/130) | 99.0% (102/103) | 99.2% (129/130) |
| xpert | PLWithHIV | 44.2% (103/233) | 129 | 1 | 1 | 102 | 83.5% (86/103) | 89.2% (116/130) | 88.3% (91/103) | 96.2% (125/130) | 74.8% (77/103) | 88.5% (115/130) | 64.1% (66/103) | 95.4% (124/130) | 93.2% (96/103) | 98.5% (128/130) | 100.0% (103/103) | 100.0% (130/130) |
| culture | PLWithoutHIV | 14.2% (38/267) | 228 | 0 | 1 | 38 | 89.5% (34/38) | 90.8% (208/229) | 81.6% (31/38) | 96.9% (222/229) | 81.6% (31/38) | 88.2% (202/229) | 57.9% (22/38) | 92.6% (212/229) | 86.8% (33/38) | 96.5% (221/229) | 100.0% (38/38) | 99.6% (228/229) |
| xpert | PLWithoutHIV | 14.6% (39/267) | 228 | 0 | 1 | 38 | 87.2% (34/39) | 90.8% (207/228) | 79.5% (31/39) | 96.9% (221/228) | 79.5% (31/39) | 88.2% (201/228) | 56.4% (22/39) | 92.5% (211/228) | 84.6% (33/39) | 96.5% (220/228) | 100.0% (39/39) | 100.0% (228/228) |
| Viet Nam District | ||||||||||||||||||
| culture | All | 1.0% (10/1000) | 979 | 0 | 11 | 10 | 90.0% (9/10) | 92.1% (912/990) | 100.0% (10/10) | 95.3% (943/990) | 80.0% (8/10) | 89.8% (889/990) | 80.0% (8/10) | 93.6% (927/990) | 90.0% (9/10) | 97.0% (960/990) | 100.0% (10/10) | 98.9% (979/990) |
| xpert | All | 2.1% (21/1000) | 979 | 0 | 11 | 10 | 47.6% (10/21) | 92.1% (902/979) | 52.4% (11/21) | 95.3% (933/979) | 42.9% (9/21) | 89.8% (879/979) | 42.9% (9/21) | 93.7% (917/979) | 42.9% (9/21) | 96.9% (949/979) | 100.0% (21/21) | 100.0% (979/979) |
| culture | PLWithHIV | 1.8% (7/398) | 386 | 0 | 5 | 7 | 85.7% (6/7) | 91.6% (358/391) | 100.0% (7/7) | 95.4% (373/391) | 100.0% (7/7) | 88.0% (344/391) | 71.4% (5/7) | 92.3% (361/391) | 100.0% (7/7) | 96.7% (378/391) | 100.0% (7/7) | 98.7% (386/391) |
| xpert | PLWithHIV | 3.0% (12/398) | 386 | 0 | 5 | 7 | 50.0% (6/12) | 91.5% (353/386) | 66.7% (8/12) | 95.6% (369/386) | 66.7% (8/12) | 88.1% (340/386) | 41.7% (5/12) | 92.2% (356/386) | 58.3% (7/12) | 96.6% (373/386) | 100.0% (12/12) | 100.0% (386/386) |
| culture | PLWithoutHIV | 0.5% (3/602) | 593 | 0 | 6 | 3 | 100.0% (3/3) | 92.5% (554/599) | 100.0% (3/3) | 95.2% (570/599) | 33.3% (1/3) | 91.0% (545/599) | 100.0% (3/3) | 94.5% (566/599) | 66.7% (2/3) | 97.2% (582/599) | 100.0% (3/3) | 99.0% (593/599) |
| xpert | PLWithoutHIV | 1.5% (9/602) | 593 | 0 | 6 | 3 | 44.4% (4/9) | 92.6% (549/593) | 33.3% (3/9) | 95.1% (564/593) | 11.1% (1/9) | 90.9% (539/593) | 44.4% (4/9) | 94.6% (561/593) | 22.2% (2/9) | 97.1% (576/593) | 100.0% (9/9) | 100.0% (593/593) |
| Viet Nam Informal settlements | ||||||||||||||||||
| culture | All | 0.7% (11/1500) | 1472 | 0 | 17 | 11 | 100.0% (11/11) | 91.9% (1368/1489) | 100.0% (11/11) | 94.2% (1403/1489) | 72.7% (8/11) | 91.1% (1356/1489) | 63.6% (7/11) | 94.7% (1410/1489) | 100.0% (11/11) | 96.6% (1438/1489) | 100.0% (11/11) | 98.9% (1472/1489) |
| xpert | All | 1.9% (28/1500) | 1472 | 0 | 17 | 11 | 42.9% (12/28) | 91.8% (1352/1472) | 42.9% (12/28) | 94.2% (1387/1472) | 46.4% (13/28) | 91.3% (1344/1472) | 28.6% (8/28) | 94.7% (1394/1472) | 46.4% (13/28) | 96.7% (1423/1472) | 100.0% (28/28) | 100.0% (1472/1472) |
| culture | PLWithHIV | 1.3% (8/603) | 587 | 0 | 8 | 8 | 100.0% (8/8) | 93.3% (555/595) | 100.0% (8/8) | 94.3% (561/595) | 75.0% (6/8) | 91.8% (546/595) | 62.5% (5/8) | 95.3% (567/595) | 100.0% (8/8) | 97.6% (581/595) | 100.0% (8/8) | 98.7% (587/595) |
| xpert | PLWithHIV | 2.7% (16/603) | 587 | 0 | 8 | 8 | 56.2% (9/16) | 93.4% (548/587) | 56.2% (9/16) | 94.4% (554/587) | 50.0% (8/16) | 92.0% (540/587) | 31.2% (5/16) | 95.2% (559/587) | 56.2% (9/16) | 97.8% (574/587) | 100.0% (16/16) | 100.0% (587/587) |
| culture | PLWithoutHIV | 0.3% (3/897) | 885 | 0 | 9 | 3 | 100.0% (3/3) | 90.9% (813/894) | 100.0% (3/3) | 94.2% (842/894) | 66.7% (2/3) | 90.6% (810/894) | 66.7% (2/3) | 94.3% (843/894) | 100.0% (3/3) | 95.9% (857/894) | 100.0% (3/3) | 99.0% (885/894) |
| xpert | PLWithoutHIV | 1.3% (12/897) | 885 | 0 | 9 | 3 | 25.0% (3/12) | 90.8% (804/885) | 25.0% (3/12) | 94.1% (833/885) | 41.7% (5/12) | 90.8% (804/885) | 25.0% (3/12) | 94.4% (835/885) | 33.3% (4/12) | 95.9% (849/885) | 100.0% (12/12) | 100.0% (885/885) |
| Viet Nam Children | ||||||||||||||||||
| culture | All | 0.0% (0/500) | 496 | 0 | 4 | 0 | . | 92.2% (461/500) | . | 93.2% (466/500) | . | 90.4% (452/500) | . | 94.2% (471/500) | . | 97.0% (485/500) | . | 99.2% (496/500) |
| xpert | All | 0.8% (4/500) | 496 | 0 | 4 | 0 | 25.0% (1/4) | 92.3% (458/496) | 0.0% (0/4) | 93.1% (462/496) | 25.0% (1/4) | 90.5% (449/496) | 0.0% (0/4) | 94.2% (467/496) | 25.0% (1/4) | 97.2% (482/496) | 100.0% (4/4) | 100.0% (496/496) |
| culture | PLWithHIV | 0.0% (0/209) | 206 | 0 | 3 | 0 | . | 94.3% (197/209) | . | 93.8% (196/209) | . | 90.0% (188/209) | . | 94.7% (198/209) | . | 96.7% (202/209) | . | 98.6% (206/209) |
| xpert | PLWithHIV | 1.4% (3/209) | 206 | 0 | 3 | 0 | 33.3% (1/3) | 94.7% (195/206) | 0.0% (0/3) | 93.7% (193/206) | 33.3% (1/3) | 90.3% (186/206) | 0.0% (0/3) | 94.7% (195/206) | 33.3% (1/3) | 97.1% (200/206) | 100.0% (3/3) | 100.0% (206/206) |
| culture | PLWithoutHIV | 0.0% (0/291) | 290 | 0 | 1 | 0 | . | 90.7% (264/291) | . | 92.8% (270/291) | . | 90.7% (264/291) | . | 93.8% (273/291) | . | 97.3% (283/291) | . | 99.7% (290/291) |
| xpert | PLWithoutHIV | 0.3% (1/291) | 290 | 0 | 1 | 0 | 0.0% (0/1) | 90.7% (263/290) | 0.0% (0/1) | 92.8% (269/290) | 0.0% (0/1) | 90.7% (263/290) | 0.0% (0/1) | 93.8% (272/290) | 0.0% (0/1) | 97.2% (282/290) | 100.0% (1/1) | 100.0% (290/290) |
| Malawi PHC | ||||||||||||||||||
| culture | All | 7.8% (93/1200) | 1096 | 1 | 11 | 92 | 90.3% (84/93) | 91.3% (1011/1107) | 91.4% (85/93) | 96.2% (1065/1107) | 81.7% (76/93) | 91.9% (1017/1107) | 71.0% (66/93) | 94.5% (1046/1107) | 90.3% (84/93) | 97.7% (1082/1107) | 98.9% (92/93) | 99.0% (1096/1107) |
| xpert | All | 8.6% (103/1200) | 1096 | 1 | 11 | 92 | 82.5% (85/103) | 91.3% (1002/1097) | 81.6% (84/103) | 96.1% (1054/1097) | 74.8% (77/103) | 91.9% (1008/1097) | 64.1% (66/103) | 94.4% (1036/1097) | 80.6% (83/103) | 97.6% (1071/1097) | 100.0% (103/103) | 100.0% (1097/1097) |
| culture | PLWithHIV | 12.8% (65/507) | 439 | 1 | 3 | 64 | 90.8% (59/65) | 92.8% (410/442) | 93.8% (61/65) | 96.6% (427/442) | 86.2% (56/65) | 93.7% (414/442) | 72.3% (47/65) | 94.6% (418/442) | 90.8% (59/65) | 98.4% (435/442) | 98.5% (64/65) | 99.3% (439/442) |
| xpert | PLWithHIV | 13.2% (67/507) | 439 | 1 | 3 | 64 | 86.6% (58/67) | 92.5% (407/440) | 89.6% (60/67) | 96.4% (424/440) | 82.1% (55/67) | 93.4% (411/440) | 68.7% (46/67) | 94.3% (415/440) | 86.6% (58/67) | 98.2% (432/440) | 100.0% (67/67) | 100.0% (440/440) |
| culture | PLWithoutHIV | 4.0% (28/693) | 657 | 0 | 8 | 28 | 89.3% (25/28) | 90.4% (601/665) | 85.7% (24/28) | 95.9% (638/665) | 71.4% (20/28) | 90.7% (603/665) | 67.9% (19/28) | 94.4% (628/665) | 89.3% (25/28) | 97.3% (647/665) | 100.0% (28/28) | 98.8% (657/665) |
| xpert | PLWithoutHIV | 5.2% (36/693) | 657 | 0 | 8 | 28 | 75.0% (27/36) | 90.6% (595/657) | 66.7% (24/36) | 95.9% (630/657) | 61.1% (22/36) | 90.9% (597/657) | 55.6% (20/36) | 94.5% (621/657) | 69.4% (25/36) | 97.3% (639/657) | 100.0% (36/36) | 100.0% (657/657) |
5.5.1.1 Fit the Bayesian models
This section only exists to hold the chunk of R code that fits the Bayesian models for all settings that we are considering. There is no other output.
Code
# prepare output data frame
dfResPrimBayes<-data.frame(
country=c(rep("Cameroon",6),rep("Nigeria",8),rep("Kenya",2),rep("Bangladesh",5),rep("Brazil",2),rep("Viet Nam",5),rep("Malawi",1),"Pooled","Pooled"),
region=c(rep("",6),c(rep("ZRC",2),rep("JHF",6)),rep("",2+5),"Aracaju","Maceio",rep("",5+1),rep("",2)),
setting=c("PHC","District",rep("Nomads",3),"Children","PHC","District",rep("Nomads",3),rep("IDP / refugees",3),"PHC","District","PHC","District",rep("Informal settlements",3),"PHC","PHC","District",rep("Informal settlements",3),"Children","PHC","PHC","District"),
entryToStudy=c(rep("W4SS",2),"W4SS","CXR","W4SS | CXR","",rep("W4SS",2),"W4SS","CXR","W4SS | CXR","W4SS","CXR","W4SS | CXR",rep("W4SS",2),rep("W4SS",2),"W4SS","CXR","W4SS | CXR",rep("W4SS",2),"W4SS","W4SS","CXR","W4SS | CXR","","W4SS",rep("W4SS",2))
) %>%
dplyr::filter(setting!="Children")
allRes<-list()
printResults<-TRUE
checkW4ssFacility<-FALSE
checkW4ssAcf<-FALSE
checkW4ssCxrAcf<-FALSE
checkCxrAcf<-FALSE
outPrefix<-"mockData_AnalysisResults_"
for(i in 1:(nrow(dfResPrimBayes)-2)){
print(i)
if(dfResPrimBayes$setting[i] %in% c("PHC","District") & dfResPrimBayes$country[i]!="Pooled"){
res<-analysisFunBayesBetaPars(dat=dfSim,c=dfResPrimBayes$country[i],r=dfResPrimBayes$region[i],s=dfResPrimBayes$setting[i],doPlot=TRUE,plotFile=paste(sep="",outPrefix,"S4A_mcmcPars_",dfResPrimBayes$country[i],"_",dfResPrimBayes$region[i],"_",gsub(pattern=" / ",replacement="_",dfResPrimBayes$setting[i]),"_",gsub(pattern="-",replacement="",Sys.Date()),".pdf"),nChains=nChains,nAdapt=nAdapt,nBurn=nBurn,nIter=nIter,jagsFile=jagsFileW4ss,parsVect=parsVectW4ssNoLR)
# derive positive and negative likelihood ratios
res$mcmcObj<-getLRpLRm(res$mcmcObj)
# format the summary
mcmcSumDf<-MCMCsummary(res$mcmcObj)
mcmcSumDf$mean<-format(nsmall=3,round(digits=3,mcmcSumDf$mean))
mcmcSumDf$sd<-format(nsmall=3,round(digits=3,mcmcSumDf$sd))
mcmcSumDf$`2.5%`<-format(nsmall=3,round(digits=3,mcmcSumDf$`2.5%`))
mcmcSumDf$`50%`<-format(nsmall=3,round(digits=3,mcmcSumDf$`50%`))
mcmcSumDf$`97.5%`<-format(nsmall=3,round(digits=3,mcmcSumDf$`97.5%`))
mcmcSumDfPrim<-mcmcSumDf[parsVectPrim,]
mcmcSumDf<-mcmcSumDf[parsVectW4ss,]
# print the results
if(printResults){
mcmcSumDfPrim %>%
kable(caption = paste(sep="","Summary of the MCMC parameter estimation (individual tests only) for country ",dfResPrimBayes$country[i],", region ",dfResPrimBayes$region[i],", setting ",dfResPrimBayes$setting[i]," (PCF/ICF set of diagnostic algorithms).\nMetrics shown are the posterior mean, standard deviation, 2.5th, 50th, 97.5th quantiles, the Gelman-Rubin potential scale reduction factor (Rhat) and the effective sample size (n.eff).")) %>%
kable_styling(full_width=FALSE)
}
# add the summary to the result object
res[["mcmcSummary"]]<-mcmcSumDf
allRes[[paste(sep="_",dfResPrimBayes$country[i],dfResPrimBayes$region[i],dfResPrimBayes$setting[i])]]<-res
values<-numeric(0)
tmpParList<-parsVectW4ss[!grepl(pattern="lrp|lrm",parsVectW4ss)]
for(j in 1:length(tmpParList)){
parTmp<-unlist(strsplit(split="\\.",tmpParList[j]))
if(length(parTmp)==1){
parTmp.ab<-paste(sep=".",parTmp[1],c("a","b"))
}else{
parTmp.ab<-paste(sep=".",parTmp[1],c("a","b"),paste(collapse=".",parTmp[2:length(parTmp)]))
}
if(!(tmpParList[j] %in% res$betaPars$par)){cat(paste(sep="","Parameter ",tmpParList[j]," not found in MCMC parameter list.\n"))}
outTmp<-unlist(res$betaPars[res$betaPars$par==tmpParList[j],c("a","b")])
names(outTmp)<-parTmp.ab
values<-c(values,outTmp)
}
}else if(dfResPrimBayes$setting[i] %in% c("IDP / refugees","Informal settlements","Nomads") & dfResPrimBayes$entryToStudy[i]=="W4SS" & dfResPrimBayes$country[i]!="Pooled"){
res<-analysisFunBayesBetaPars(dat=dfSim %>% filter(!is.na(w4ss) & w4ss==1),c=dfResPrimBayes$country[i],r=dfResPrimBayes$region[i],s=dfResPrimBayes$setting[i],doPlot=TRUE,plotFile=paste(sep="",outPrefix,"S4A_mcmcPars_",dfResPrimBayes$country[i],"_",dfResPrimBayes$region[i],"_",gsub(pattern=" / ",replacement="_",dfResPrimBayes$setting[i]),"_",gsub(pattern="-",replacement="",Sys.Date()),".pdf"),nChains=nChains,nAdapt=nAdapt,nBurn=nBurn,nIter=nIter,jagsFile=jagsFileW4ss,parsVect=parsVectW4ssNoLR)
# derive positive and negative likelihood ratios
res$mcmcObj<-getLRpLRm(res$mcmcObj)
# format the summary
mcmcSumDf<-MCMCsummary(res$mcmcObj)
mcmcSumDf$mean<-format(nsmall=3,round(digits=3,mcmcSumDf$mean))
mcmcSumDf$sd<-format(nsmall=3,round(digits=3,mcmcSumDf$sd))
mcmcSumDf$`2.5%`<-format(nsmall=3,round(digits=3,mcmcSumDf$`2.5%`))
mcmcSumDf$`50%`<-format(nsmall=3,round(digits=3,mcmcSumDf$`50%`))
mcmcSumDf$`97.5%`<-format(nsmall=3,round(digits=3,mcmcSumDf$`97.5%`))
mcmcSumDfPrim<-mcmcSumDf[parsVectPrim,]
mcmcSumDf<-mcmcSumDf[parsVectW4ss,]
# print the results
if(printResults){
mcmcSumDfPrim %>%
kable(caption = paste(sep="","Summary of the MCMC parameter estimation (individual tests only) for country ",dfResPrimBayes$country[i],", region ",dfResPrimBayes$region[i],", setting ",dfResPrimBayes$setting[i]," (ACF set of diagnostic algorithms, W4SS entry).\nMetrics shown are the posterior mean, standard deviation, 2.5th, 50th, 97.5th quantiles, the Gelman-Rubin potential scale reduction factor (Rhat) and the effective sample size (n.eff).")) %>%
kable_styling(full_width=FALSE)
}
# add the summary to the result object
res[["mcmcSummary"]]<-mcmcSumDf
allRes[[paste(sep="_",dfResPrimBayes$country[i],dfResPrimBayes$region[i],dfResPrimBayes$setting[i])]]<-res
values<-numeric(0)
tmpParList<-parsVectW4ss[!grepl(pattern="lrp|lrm",parsVectW4ss)]
for(j in 1:length(tmpParList)){
parTmp<-unlist(strsplit(split="\\.",tmpParList[j]))
if(length(parTmp)==1){
parTmp.ab<-paste(sep=".",parTmp[1],c("a","b"))
}else{
parTmp.ab<-paste(sep=".",parTmp[1],c("a","b"),paste(collapse=".",parTmp[2:length(parTmp)]))
}
if(!(tmpParList[j] %in% res$betaPars$par)){cat(paste(sep="","Parameter ",tmpParList[j]," not found in MCMC parameter list.\n"))}
outTmp<-unlist(res$betaPars[res$betaPars$par==tmpParList[j],c("a","b")])
names(outTmp)<-parTmp.ab
values<-c(values,outTmp)
}
}else if(dfResPrimBayes$setting[i] %in% c("IDP / refugees","Informal settlements","Nomads") & dfResPrimBayes$entryToStudy[i]=="CXR" & dfResPrimBayes$country[i]!="Pooled"){
res<-analysisFunBayesBetaPars(dat=dfSim %>% filter(!is.na(cxr) & cxr==1),c=dfResPrimBayes$country[i],r=dfResPrimBayes$region[i],s=dfResPrimBayes$setting[i],doPlot=TRUE,plotFile=paste(sep="",outPrefix,"S4A_mcmcPars_",dfResPrimBayes$country[i],"_",dfResPrimBayes$region[i],"_",gsub(pattern=" / ",replacement="_",dfResPrimBayes$setting[i]),"_",gsub(pattern="-",replacement="",Sys.Date()),".pdf"),nChains=nChains,nAdapt=nAdapt,nBurn=nBurn,nIter=nIter,jagsFile=jagsFileCxr,parsVect=parsVectCxrNoLR)
# derive positive and negative likelihood ratios
res$mcmcObj<-getLRpLRm(res$mcmcObj)
# format the summary
mcmcSumDf<-MCMCsummary(res$mcmcObj)
mcmcSumDf$mean<-format(nsmall=3,round(digits=3,mcmcSumDf$mean))
mcmcSumDf$sd<-format(nsmall=3,round(digits=3,mcmcSumDf$sd))
mcmcSumDf$`2.5%`<-format(nsmall=3,round(digits=3,mcmcSumDf$`2.5%`))
mcmcSumDf$`50%`<-format(nsmall=3,round(digits=3,mcmcSumDf$`50%`))
mcmcSumDf$`97.5%`<-format(nsmall=3,round(digits=3,mcmcSumDf$`97.5%`))
mcmcSumDfPrim<-mcmcSumDf[parsVectPrim,]
mcmcSumDf<-mcmcSumDf[parsVectCxr,]
# print the results
if(printResults){
mcmcSumDfPrim %>%
kable(caption = paste(sep="","Summary of the MCMC parameter estimation (individual tests only) for country ",dfResPrimBayes$country[i],", region ",dfResPrimBayes$region[i],", setting ",dfResPrimBayes$setting[i]," (ACF set of diagnostic algorithms, CXR-CAD entry).\nMetrics shown are the posterior mean, standard deviation, 2.5th, 50th, 97.5th quantiles, the Gelman-Rubin potential scale reduction factor (Rhat) and the effective sample size (n.eff).")) %>%
kable_styling(full_width=FALSE)
}
# add the summary to the result object
res[["mcmcSummary"]]<-mcmcSumDf
allRes[[paste(sep="_",dfResPrimBayes$country[i],dfResPrimBayes$region[i],dfResPrimBayes$setting[i])]]<-res
values<-numeric(0)
tmpParList<-parsVectCxr[!grepl(pattern="lrp|lrm",parsVectCxr)]
for(j in 1:length(tmpParList)){
parTmp<-unlist(strsplit(split="\\.",tmpParList[j]))
if(length(parTmp)==1){
parTmp.ab<-paste(sep=".",parTmp[1],c("a","b"))
}else{
parTmp.ab<-paste(sep=".",parTmp[1],c("a","b"),paste(collapse=".",parTmp[2:length(parTmp)]))
}
if(!(tmpParList[j] %in% res$betaPars$par)){cat(paste(sep="","Parameter ",tmpParList[j]," not found in MCMC parameter list.\n"))}
outTmp<-unlist(res$betaPars[res$betaPars$par==tmpParList[j],c("a","b")])
names(outTmp)<-parTmp.ab
values<-c(values,outTmp)
}
}else if(dfResPrimBayes$setting[i] %in% c("IDP / refugees","Informal settlements","Nomads") & dfResPrimBayes$entryToStudy[i]=="W4SS | CXR" & dfResPrimBayes$country[i]!="Pooled"){
res<-analysisFunBayesBetaPars(dat=dfSim %>% filter((!is.na(w4ss) & w4ss==1) | (!is.na(cxr) & cxr==1)),c=dfResPrimBayes$country[i],r=dfResPrimBayes$region[i],s=dfResPrimBayes$setting[i],doPlot=TRUE,plotFile=paste(sep="",outPrefix,"S4A_mcmcPars_",dfResPrimBayes$country[i],"_",dfResPrimBayes$region[i],"_",gsub(pattern=" / ",replacement="_",dfResPrimBayes$setting[i]),"_",gsub(pattern="-",replacement="",Sys.Date()),".pdf"),nChains=nChains,nAdapt=nAdapt,nBurn=nBurn,nIter=nIter,jagsFile=jagsFileCxr,parsVect=parsVectCxrNoLR)
# derive positive and negative likelihood ratios
res$mcmcObj<-getLRpLRm(res$mcmcObj)
# format the summary
mcmcSumDf<-MCMCsummary(res$mcmcObj)
mcmcSumDf$mean<-format(nsmall=3,round(digits=3,mcmcSumDf$mean))
mcmcSumDf$sd<-format(nsmall=3,round(digits=3,mcmcSumDf$sd))
mcmcSumDf$`2.5%`<-format(nsmall=3,round(digits=3,mcmcSumDf$`2.5%`))
mcmcSumDf$`50%`<-format(nsmall=3,round(digits=3,mcmcSumDf$`50%`))
mcmcSumDf$`97.5%`<-format(nsmall=3,round(digits=3,mcmcSumDf$`97.5%`))
mcmcSumDfPrim<-mcmcSumDf[parsVectPrim,]
mcmcSumDf<-mcmcSumDf[parsVectCxr,]
# print the results
if(printResults){
mcmcSumDfPrim %>%
kable(caption = paste(sep="","Summary of the MCMC parameter estimation (individual tests only) for country ",dfResPrimBayes$country[i],", region ",dfResPrimBayes$region[i],", setting ",dfResPrimBayes$setting[i]," (ACF set of diagnostic algorithms, W4SS | CXR-CAD entry).\nMetrics shown are the posterior mean, standard deviation, 2.5th, 50th, 97.5th quantiles, the Gelman-Rubin potential scale reduction factor (Rhat) and the effective sample size (n.eff).")) %>%
kable_styling(full_width=FALSE)
}
# add the summary to the result object
res[["mcmcSummary"]]<-mcmcSumDf
allRes[[paste(sep="_",dfResPrimBayes$country[i],dfResPrimBayes$region[i],dfResPrimBayes$setting[i])]]<-res
values<-numeric(0)
tmpParList<-parsVectCxr[!grepl(pattern="lrp|lrm",parsVectCxr)]
for(j in 1:length(tmpParList)){
parTmp<-unlist(strsplit(split="\\.",tmpParList[j]))
if(length(parTmp)==1){
parTmp.ab<-paste(sep=".",parTmp[1],c("a","b"))
}else{
parTmp.ab<-paste(sep=".",parTmp[1],c("a","b"),paste(collapse=".",parTmp[2:length(parTmp)]))
}
if(!(tmpParList[j] %in% res$betaPars$par)){cat(paste(sep="","Parameter ",tmpParList[j]," not found in MCMC parameter list.\n"))}
outTmp<-unlist(res$betaPars[res$betaPars$par==tmpParList[j],c("a","b")])
names(outTmp)<-parTmp.ab
values<-c(values,outTmp)
}
}else if(dfResPrimBayes$setting[i]=="Children" & dfResPrimBayes$country[i]!="Pooled"){
cat("Children processing not yet implemented.\n")
values<-NA
}else if(dfResPrimBayes$country[i]!="Pooled"){
stop("Invalid setting parameter.")
}
if(!checkW4ssFacility & dfResPrimBayes$setting[i] %in% c("PHC","District") & dfResPrimBayes$country[i]!="Pooled"){
dfResW4ssFacility<-values
checkW4ssFacility<-TRUE
}else if(checkW4ssFacility & dfResPrimBayes$setting[i] %in% c("PHC","District") & dfResPrimBayes$country[i]!="Pooled"){
dfResW4ssFacility<-rbind(dfResW4ssFacility,values)
}else if(!checkW4ssAcf & dfResPrimBayes$setting[i] %in% c("IDP / refugees","Informal settlements","Nomads") & dfResPrimBayes$country[i]!="Pooled" & dfResPrimBayes$entryToStudy[i]=="W4SS"){
dfResW4ssAcf<-values
checkW4ssAcf<-TRUE
}else if(checkW4ssAcf & dfResPrimBayes$setting[i] %in% c("IDP / refugees","Informal settlements","Nomads") & dfResPrimBayes$country[i]!="Pooled" & dfResPrimBayes$entryToStudy[i]=="W4SS"){
dfResW4ssAcf<-rbind(dfResW4ssAcf,values)
}else if(!checkCxrAcf & dfResPrimBayes$setting[i] %in% c("IDP / refugees","Informal settlements","Nomads") & dfResPrimBayes$country[i]!="Pooled" & dfResPrimBayes$entryToStudy[i]=="CXR"){
dfResCxrAcf<-values
checkCxrAcf<-TRUE
}else if(checkCxrAcf & dfResPrimBayes$setting[i] %in% c("IDP / refugees","Informal settlements","Nomads") & dfResPrimBayes$country[i]!="Pooled" & dfResPrimBayes$entryToStudy[i]=="CXR"){
dfResCxrAcf<-rbind(dfResCxrAcf,values)
}else if(!checkW4ssCxrAcf & dfResPrimBayes$setting[i] %in% c("IDP / refugees","Informal settlements","Nomads") & dfResPrimBayes$country[i]!="Pooled" & dfResPrimBayes$entryToStudy[i]=="W4SS | CXR"){
dfResW4ssCxrAcf<-values
checkW4ssCxrAcf<-TRUE
}else if(checkW4ssCxrAcf & dfResPrimBayes$setting[i] %in% c("IDP / refugees","Informal settlements","Nomads") & dfResPrimBayes$country[i]!="Pooled" & dfResPrimBayes$entryToStudy[i]=="W4SS | CXR"){
dfResW4ssCxrAcf<-rbind(dfResW4ssCxrAcf,values)
}
}[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 6
[1] 7
[1] 8
[1] 9
[1] 10
[1] 11
[1] 12
[1] 13
[1] 14
[1] 15
[1] 16
[1] 17
[1] 18
[1] 19
[1] 20
[1] 21
[1] 22
[1] 23
[1] 24
[1] 25
[1] 26
[1] 27
Code
# Pooled PHC
res<-analysisFunBayesBetaParsPool(dat=dfSim,set="PHC",doPlot=TRUE,plotFile=paste(sep="",outPrefix,"S4A_mcmcPars_Pooled_PHC","_",gsub(pattern="-",replacement="",Sys.Date()),".pdf"),nChains=nChains,nAdapt=nAdapt,nBurn=nBurn,nIter=nIter,jagsFile=jagsFileW4ssPooled,parsVect=parsVectW4ssNoLR)NOTE: Stopping adaptation
Code
## derive positive and negative likelihood ratios
res$mcmcObj<-getLRpLRm(res$mcmcObj)
## format the summary
mcmcSumDf<-MCMCsummary(res$mcmcObj)
mcmcSumDf$mean<-format(nsmall=3,round(digits=3,mcmcSumDf$mean))
mcmcSumDf$sd<-format(nsmall=3,round(digits=3,mcmcSumDf$sd))
mcmcSumDf$`2.5%`<-format(nsmall=3,round(digits=3,mcmcSumDf$`2.5%`))
mcmcSumDf$`50%`<-format(nsmall=3,round(digits=3,mcmcSumDf$`50%`))
mcmcSumDf$`97.5%`<-format(nsmall=3,round(digits=3,mcmcSumDf$`97.5%`))
mcmcSumDfPrim<-mcmcSumDf[parsVectPrim,]
mcmcSumDf<-mcmcSumDf[parsVectW4ss,]
# add the summary to the result object
res[["mcmcSummary"]]<-mcmcSumDf
allRes[["Pooled__PHC"]]<-res
values<-numeric(0)
tmpParList<-parsVectW4ss[!grepl(pattern="lrp|lrm",parsVectW4ss)]
for(j in 1:length(tmpParList)){
parTmp<-unlist(strsplit(split="\\.",tmpParList[j]))
if(length(parTmp)==1){
parTmp.ab<-paste(sep=".",parTmp[1],c("a","b"))
}else{
parTmp.ab<-paste(sep=".",parTmp[1],c("a","b"),paste(collapse=".",parTmp[2:length(parTmp)]))
}
if(!(tmpParList[j] %in% res$betaPars$par)){cat(paste(sep="","Parameter ",tmpParList[j]," not found in MCMC parameter list.\n"))}
outTmp<-unlist(res$betaPars[res$betaPars$par==tmpParList[j],c("a","b")])
names(outTmp)<-parTmp.ab
values<-c(values,outTmp)
}
dfResW4ssFacility<-rbind(dfResW4ssFacility,values)
# Pooled district
res<-analysisFunBayesBetaParsPool(dat=dfSim,set="District",doPlot=TRUE,plotFile=paste(sep="",outPrefix,"S4A_mcmcPars_Pooled_District","_",gsub(pattern="-",replacement="",Sys.Date()),".pdf"),nChains=nChains,nAdapt=nAdapt,nBurn=nBurn,nIter=nIter,jagsFile=jagsFileW4ssPooled,parsVect=parsVectW4ssNoLR)NOTE: Stopping adaptation
Code
## derive positive and negative likelihood ratios
res$mcmcObj<-getLRpLRm(res$mcmcObj)
## format the summary
mcmcSumDf<-MCMCsummary(res$mcmcObj)
mcmcSumDf$mean<-format(nsmall=3,round(digits=3,mcmcSumDf$mean))
mcmcSumDf$sd<-format(nsmall=3,round(digits=3,mcmcSumDf$sd))
mcmcSumDf$`2.5%`<-format(nsmall=3,round(digits=3,mcmcSumDf$`2.5%`))
mcmcSumDf$`50%`<-format(nsmall=3,round(digits=3,mcmcSumDf$`50%`))
mcmcSumDf$`97.5%`<-format(nsmall=3,round(digits=3,mcmcSumDf$`97.5%`))
mcmcSumDfPrim<-mcmcSumDf[parsVectPrim,]
mcmcSumDf<-mcmcSumDf[parsVectW4ss,]
# add the summary to the result object
res[["mcmcSummary"]]<-mcmcSumDf
allRes[["Pooled__District"]]<-res
values<-numeric(0)
tmpParList<-parsVectW4ss[!grepl(pattern="lrp|lrm",parsVectW4ss)]
for(j in 1:length(tmpParList)){
parTmp<-unlist(strsplit(split="\\.",tmpParList[j]))
if(length(parTmp)==1){
parTmp.ab<-paste(sep=".",parTmp[1],c("a","b"))
}else{
parTmp.ab<-paste(sep=".",parTmp[1],c("a","b"),paste(collapse=".",parTmp[2:length(parTmp)]))
}
if(!(tmpParList[j] %in% res$betaPars$par)){cat(paste(sep="","Parameter ",tmpParList[j]," not found in MCMC parameter list.\n"))}
outTmp<-unlist(res$betaPars[res$betaPars$par==tmpParList[j],c("a","b")])
names(outTmp)<-parTmp.ab
values<-c(values,outTmp)
}
dfResW4ssFacility<-rbind(dfResW4ssFacility,values)
if(!is.null(dim(dfResW4ssFacility))){
dfResW4ssFacility<-cbind(dfResPrimBayes %>% dplyr::filter(setting %in% c("PHC","District")),dfResW4ssFacility)
colnames(dfResW4ssFacility)<-c(colnames(dfResPrimBayes),parsVectW4ss)
}else{
dfResW4ssFacility<-as.character(c(dfResPrimBayes %>% dplyr::filter(setting %in% c("PHC","District")),dfResW4ssFacility))
names(dfResW4ssFacility)<-c(colnames(dfResPrimBayes),parsVectW4ss)
dfResW4ssFacility<-t(as.data.frame(dfResW4ssFacility))
}
if(!is.null(dim(dfResW4ssAcf))){
dfResW4ssAcf<-cbind(dfResPrimBayes %>% dplyr::filter(setting %in% c("IDP / refugees","Informal settlements","Nomads") & entryToStudy=="W4SS"),dfResW4ssAcf)
colnames(dfResW4ssAcf)<-c(colnames(dfResPrimBayes),parsVectW4ss)
}else{
dfResW4ssAcf<-as.character(c(dfResPrimBayes %>% dplyr::filter(setting %in% c("IDP / refugees","Informal settlements","Nomads") & entryToStudy=="W4SS"),dfResW4ssAcf))
names(dfResW4ssAcf)<-c(colnames(dfResPrimBayes),parsVectW4ss)
dfResW4ssAcf<-t(as.data.frame(dfResW4ssAcf))
}
if(!is.null(dim(dfResCxrAcf))){
dfResCxrAcf<-cbind(dfResPrimBayes %>% dplyr::filter(setting %in% c("IDP / refugees","Informal settlements","Nomads") & entryToStudy=="CXR"),dfResCxrAcf)
colnames(dfResCxrAcf)<-c(colnames(dfResPrimBayes),parsVectCxr)
}else{
dfResCxrAcf<-as.character(c(dfResPrimBayes %>% dplyr::filter(setting %in% c("IDP / refugees","Informal settlements","Nomads") & entryToStudy=="CXR"),dfResCxrAcf))
names(dfResCxrAcf)<-c(colnames(dfResPrimBayes),parsVectCxr)
dfResCxrAcf<-t(as.data.frame(dfResCxrAcf))
}
if(!is.null(dim(dfResW4ssCxrAcf))){
dfResW4ssCxrAcf<-cbind(dfResPrimBayes %>% dplyr::filter(setting %in% c("IDP / refugees","Informal settlements","Nomads") & entryToStudy=="W4SS | CXR"),dfResW4ssCxrAcf)
colnames(dfResW4ssCxrAcf)<-c(colnames(dfResPrimBayes),parsVectCxr)
}else{
dfResW4ssCxrAcf<-as.character(c(dfResPrimBayes %>% dplyr::filter(setting %in% c("IDP / refugees","Informal settlements","Nomads") & entryToStudy=="W4SS | CXR"),dfResW4ssCxrAcf))
names(dfResW4ssCxrAcf)<-c(colnames(dfResPrimBayes),parsVectCxr)
dfResW4ssCxrAcf<-t(as.data.frame(dfResW4ssCxrAcf))
}
write.csv(dfResW4ssFacility,row.names=F,file=paste(sep="","mockData_AnalysisResults_PCFICF_",gsub(pattern="-",replacement="",Sys.Date()),".csv"))
write.csv(dfResW4ssAcf,row.names=F,file=paste(sep="","mockData_AnalysisResults_ACF_W4SSentry",gsub(pattern="-",replacement="",Sys.Date()),".csv"))
write.csv(dfResCxrAcf,row.names=F,file=paste(sep="","mockData_AnalysisResults_ACF_CXRentry",gsub(pattern="-",replacement="",Sys.Date()),".csv"))
write.csv(dfResW4ssCxrAcf,row.names=F,file=paste(sep="","mockData_AnalysisResults_ACF_W4SSorCXRentry",gsub(pattern="-",replacement="",Sys.Date()),".csv"))
save(list=c("allRes","dfResPrimBayes"),file=paste(sep="","mockData_AnalysisResults_",gsub(pattern="-",replacement="",Sys.Date()),".RData"))5.5.1.2 PCF / ICF lowest level of care
Below in Table 10 we present how we plan to present results for the overall PCF/ICF evaluation at lowest levels of primary care.
Code
algoNames<-c("Poolxpert.Xpert",
"Xpert",
"Lam",
"Cxr.Poolxpert.Xpert",
"Crp.Poolxpert.Xpert",
"Lam.Poolxpert.Xpert",
"CxrCrpLam.Poolxpert.Xpert",
"CxrLam.Poolxpert.Xpert",
"CrpLam.Poolxpert.Xpert",
"CxrCrp.Poolxpert.Xpert",
"Cxr.Xpert",
"Crp.Xpert",
"Lam.Xpert",
"CxrCrpLam.Xpert",
"CxrLam.Xpert",
"CrpLam.Xpert",
"CxrCrp.Xpert",
"Cxr.Lam",
"Crp.Lam",
"CxrCrp.Lam"
)
algoLabels<-c("Pooled Xpert Ultra --> Xpert Ultra",
"Xpert Ultra",
"LAM",
"CXR-CAD --> Pooled Xpert Ultra --> Xpert Ultra",
"CRP --> Pooled Xpert Ultra --> Xpert Ultra",
"Lam --> Poolxpert --> Xpert",
"CXR-CAD | CRP | LAM --> Pooled Xpert Ultra --> Xpert Ultra",
"CXR-CAD | LAM --> Pooled Xpert Ultra --> Xpert Ultra",
"CRP | LAM --> Pooled Xpert Ultra --> Xpert Ultra",
"CXR-CAD | CRP --> Pooled Xpert Ultra --> Xpert Ultra",
"CXR-CAD --> Xpert Ultra",
"CRP --> Xpert Ultra",
"LAM --> Xpert Ultra",
"CXR-CAD | CRP | LAM --> Xpert Ultra",
"CXR-CAD | LAM --> Xpert Ultra",
"CRP | LAM --> Xpert Ultra",
"CXR-CAD | CRP --> Xpert Ultra",
"CXR-CAD --> LAM",
"CRP --> LAM",
"CXR-CAD | CRP --> LAM"
)
settings<-paste(sep="_",dfResPrimBayes$country,dfResPrimBayes$region,dfResPrimBayes$setting)
settings<-settings[grepl(pattern="PHC",settings)]
settings<-settings[c(length(settings),1:(length(settings)-1))]
gr<-expand.grid(settings,algoNames)
dfAlgos<-data.frame(
setting=gr[,1],
algo=gr[,2],
label=algoLabels[match(gr[,2],algoNames)],
prev=NA,
prevAS=NA,
sens=NA,
spec=NA,
ppv=NA,
npv=NA,
dyt=NA,
lrp=NA,
lrm=NA
)
for(j in 1:nrow(dfAlgos)){
res<-allRes[[as.character(dfAlgos$setting[j])]]
par<-dfAlgos$algo[j]
# prevalence
pointEstimate<-gsub(pattern=" ",replacement="",res$mcmcSummary["ptb","50%"])
ci<-paste(sep="","(",gsub(pattern=" ",replacement="",paste(collapse=",",res$mcmcSummary["ptb",c("2.5%","97.5%")])),")")
dfAlgos$prev[j]<-paste(sep=" ",pointEstimate,ci)
# prevalence of asymptomatics
tmp<-unlist(strsplit(split="_",as.character(dfAlgos$setting[j])))
if(tmp[1]!="Pooled"){
dfTmp<-dfSim %>% filter(country==tmp[1] & region==tmp[2] & setting==tmp[3])
}else{
dfTmp<-dfSim %>% filter(setting==tmp[3])
}
k<-sum(!dfTmp$w4ss)
n<-nrow(dfTmp)
pointEstimate<-round(digits=4,k/n)
ci<-round(digits=4,binom.test(x=k,n=n)$conf.int)
ci<-paste(sep="","(",gsub(pattern=" ",replacement="",paste(collapse=",",ci)),")")
dfAlgos$prevAS[j]<-paste(sep=" ",pointEstimate,ci)
# sensitivity
pointEstimate<-gsub(pattern=" ",replacement="",res$mcmcSummary[paste(sep="","pse.",par),"50%"])
ci<-paste(sep="","(",gsub(pattern=" ",replacement="",paste(collapse=",",res$mcmcSummary[paste(sep="","pse.",par),c("2.5%","97.5%")])),")")
dfAlgos$sens[j]<-paste(sep=" ",pointEstimate,ci)
# specificity
pointEstimate<-gsub(pattern=" ",replacement="",res$mcmcSummary[paste(sep="","psp.",par),"50%"])
ci<-paste(sep="","(",gsub(pattern=" ",replacement="",paste(collapse=",",res$mcmcSummary[paste(sep="","psp.",par),c("2.5%","97.5%")])),")")
dfAlgos$spec[j]<-paste(sep=" ",pointEstimate,ci)
# PPV
pointEstimate<-gsub(pattern=" ",replacement="",res$mcmcSummary[paste(sep="","ppv.",par),"50%"])
ci<-paste(sep="","(",gsub(pattern=" ",replacement="",paste(collapse=",",res$mcmcSummary[paste(sep="","ppv.",par),c("2.5%","97.5%")])),")")
dfAlgos$ppv[j]<-paste(sep=" ",pointEstimate,ci)
# NPV
pointEstimate<-gsub(pattern=" ",replacement="",res$mcmcSummary[paste(sep="","npv.",par),"50%"])
ci<-paste(sep="","(",gsub(pattern=" ",replacement="",paste(collapse=",",res$mcmcSummary[paste(sep="","npv.",par),c("2.5%","97.5%")])),")")
dfAlgos$npv[j]<-paste(sep=" ",pointEstimate,ci)
# DYT
pointEstimate<-gsub(pattern=" ",replacement="",res$mcmcSummary[paste(sep="","dyt.",par),"50%"])
ci<-paste(sep="","(",gsub(pattern=" ",replacement="",paste(collapse=",",res$mcmcSummary[paste(sep="","dyt.",par),c("2.5%","97.5%")])),")")
dfAlgos$dyt[j]<-paste(sep=" ",pointEstimate,ci)
# LR+
pointEstimate<-gsub(pattern=" ",replacement="",res$mcmcSummary[paste(sep="","lrp.",par),"50%"])
ci<-paste(sep="","(",gsub(pattern=" ",replacement="",paste(collapse=",",res$mcmcSummary[paste(sep="","lrp.",par),c("2.5%","97.5%")])),")")
dfAlgos$lrp[j]<-paste(sep=" ",pointEstimate,ci)
# LR-
pointEstimate<-gsub(pattern=" ",replacement="",res$mcmcSummary[paste(sep="","lrm.",par),"50%"])
ci<-paste(sep="","(",gsub(pattern=" ",replacement="",paste(collapse=",",res$mcmcSummary[paste(sep="","lrm.",par),c("2.5%","97.5%")])),")")
dfAlgos$lrm[j]<-paste(sep=" ",pointEstimate,ci)
}
dfAlgos$setting<-gsub(pattern="_+",replacement=" ",dfAlgos$setting)
colnames(dfAlgos)<-case_when(
colnames(dfAlgos)=="setting"~"Country & setting",
colnames(dfAlgos)=="algo"~"Algorithm code",
colnames(dfAlgos)=="label"~"Algorithm",
colnames(dfAlgos)=="prev"~"Prevalence",
colnames(dfAlgos)=="prevAS"~"Prevalence of asymptomatics",
colnames(dfAlgos)=="sens"~"Sensitivity",
colnames(dfAlgos)=="spec"~"Specificity",
colnames(dfAlgos)=="ppv"~"PPV",
colnames(dfAlgos)=="npv"~"NPV",
colnames(dfAlgos)=="dyt"~"DYT",
colnames(dfAlgos)=="dyd"~"DYD",
colnames(dfAlgos)=="lrp"~"Positive LR",
colnames(dfAlgos)=="lrm"~"Negative LR"
)
dfAlgos %>%
dplyr::select(!contains("code") & !contains("DYD") & !contains("Algorithm")) %>%
kable(caption="PCF/ICF algorithm evaluation for PHC / lowest levels of primary care settings (all participants). Asymptomatics proportions are estimated directly, using exact binomial confidence intervals, from the data (not modelled). All other parameters are posterior estimates from the Bayesian modelling approach.") %>%
kableExtra::kable_styling(full_width = FALSE) %>%
kableExtra::group_rows(index=table(fct_inorder(dfAlgos$Algorithm)))| Country & setting | Prevalence | Prevalence of asymptomatics | Sensitivity | Specificity | PPV | NPV | DYT | Positive LR | Negative LR |
|---|---|---|---|---|---|---|---|---|---|
| Pooled Xpert Ultra --> Xpert Ultra | |||||||||
| Pooled PHC | 0.113 (0.105,0.121) | 0.5984 (0.5854,0.6113) | 0.907 (0.882,0.928) | 1.000 (0.999,1.000) | 0.996 (0.989,0.999) | 0.988 (0.985,0.991) | 0.103 (0.095,0.111) | 2234.554 (747.042,12687.328) | 0.093 (0.072,0.118) |
| Cameroon PHC | 0.079 (0.063,0.097) | 0.617 (0.5861,0.6472) | 0.937 (0.868,0.976) | 0.999 (0.995,1.000) | 0.986 (0.944,0.999) | 0.995 (0.988,0.998) | 0.075 (0.060,0.093) | 828.991 (194.858,11271.903) | 0.063 (0.024,0.132) |
| Nigeria ZRC PHC | 0.219 (0.191,0.248) | 0.5271 (0.4894,0.5647) | 0.902 (0.849,0.943) | 1.000 (0.996,1.000) | 0.999 (0.986,1.000) | 0.973 (0.958,0.985) | 0.197 (0.169,0.228) | 4983.400 (232.215,92699.103) | 0.098 (0.057,0.151) |
| Kenya PHC | 0.084 (0.066,0.106) | 0.6086 (0.5713,0.6449) | 0.915 (0.828,0.969) | 0.998 (0.993,1.000) | 0.982 (0.922,0.999) | 0.992 (0.983,0.997) | 0.078 (0.060,0.100) | 562.867 (135.202,7490.759) | 0.086 (0.031,0.172) |
| Bangladesh PHC | 0.034 (0.024,0.046) | 0.65 (0.6195,0.6796) | 0.853 (0.711,0.944) | 1.000 (0.998,1.000) | 0.997 (0.933,1.000) | 0.995 (0.989,0.998) | 0.029 (0.020,0.041) | 8425.700 (420.568,91621.980) | 0.147 (0.056,0.289) |
| Brazil Aracaju PHC | 0.148 (0.120,0.180) | 0.568 (0.5233,0.6119) | 0.906 (0.824,0.959) | 1.000 (0.995,1.000) | 0.999 (0.972,1.000) | 0.984 (0.969,0.993) | 0.134 (0.107,0.165) | 4141.882 (192.463,93558.389) | 0.095 (0.042,0.176) |
| Brazil Maceio PHC | 0.282 (0.246,0.320) | 0.494 (0.4493,0.5387) | 0.915 (0.862,0.954) | 1.000 (0.994,1.000) | 0.999 (0.985,1.000) | 0.967 (0.946,0.983) | 0.258 (0.221,0.297) | 3258.508 (160.140,93579.697) | 0.085 (0.046,0.138) |
| Malawi PHC | 0.078 (0.064,0.093) | 0.6317 (0.6037,0.659) | 0.893 (0.819,0.945) | 1.000 (0.998,1.000) | 0.999 (0.975,1.000) | 0.991 (0.984,0.996) | 0.069 (0.056,0.084) | 10244.805 (484.674,92950.521) | 0.107 (0.055,0.181) |
| Xpert Ultra | |||||||||
| Pooled PHC | 0.113 (0.105,0.121) | 0.5984 (0.5854,0.6113) | 0.986 (0.970,0.995) | 0.991 (0.987,0.993) | 0.931 (0.908,0.949) | 0.998 (0.996,0.999) | 0.120 (0.112,0.128) | 105.845 (77.787,144.207) | 0.014 (0.005,0.030) |
| Cameroon PHC | 0.079 (0.063,0.097) | 0.617 (0.5861,0.6472) | 0.983 (0.946,0.998) | 0.995 (0.988,0.998) | 0.942 (0.874,0.976) | 0.999 (0.995,1.000) | 0.082 (0.067,0.101) | 187.665 (81.896,455.942) | 0.017 (0.002,0.054) |
| Nigeria ZRC PHC | 0.219 (0.191,0.248) | 0.5271 (0.4894,0.5647) | 0.967 (0.933,0.986) | 0.988 (0.976,0.994) | 0.956 (0.916,0.979) | 0.991 (0.981,0.996) | 0.221 (0.193,0.251) | 77.050 (40.508,158.840) | 0.034 (0.014,0.068) |
| Kenya PHC | 0.084 (0.066,0.106) | 0.6086 (0.5713,0.6449) | 0.991 (0.960,1.000) | 0.987 (0.975,0.993) | 0.877 (0.778,0.935) | 0.999 (0.996,1.000) | 0.096 (0.076,0.119) | 77.975 (39.034,149.366) | 0.009 (0.000,0.041) |
| Bangladesh PHC | 0.034 (0.024,0.046) | 0.65 (0.6195,0.6796) | 0.993 (0.944,1.000) | 0.987 (0.978,0.993) | 0.727 (0.594,0.841) | 1.000 (0.998,1.000) | 0.047 (0.035,0.060) | 75.579 (45.974,138.593) | 0.007 (0.000,0.057) |
| Brazil Aracaju PHC | 0.148 (0.120,0.180) | 0.568 (0.5233,0.6119) | 0.974 (0.917,0.993) | 0.997 (0.989,0.999) | 0.982 (0.936,0.997) | 0.995 (0.985,0.999) | 0.147 (0.118,0.178) | 317.182 (86.871,1848.178) | 0.026 (0.007,0.084) |
| Brazil Maceio PHC | 0.282 (0.246,0.320) | 0.494 (0.4493,0.5387) | 0.989 (0.963,0.996) | 0.995 (0.987,0.999) | 0.987 (0.966,0.998) | 0.996 (0.985,0.999) | 0.282 (0.246,0.320) | 191.571 (73.281,1146.195) | 0.011 (0.004,0.037) |
| Malawi PHC | 0.078 (0.064,0.093) | 0.6317 (0.6037,0.659) | 0.989 (0.951,0.999) | 0.990 (0.982,0.995) | 0.889 (0.813,0.942) | 0.999 (0.996,1.000) | 0.086 (0.072,0.103) | 95.059 (53.893,182.423) | 0.011 (0.001,0.049) |
| LAM | |||||||||
| Pooled PHC | 0.113 (0.105,0.121) | 0.5984 (0.5854,0.6113) | 0.808 (0.768,0.841) | 0.899 (0.889,0.907) | 0.503 (0.471,0.536) | 0.973 (0.968,0.978) | 0.181 (0.171,0.192) | 7.964 (7.178,8.789) | 0.214 (0.177,0.258) |
| Cameroon PHC | 0.079 (0.063,0.097) | 0.617 (0.5861,0.6472) | 0.820 (0.727,0.895) | 0.890 (0.867,0.909) | 0.389 (0.319,0.464) | 0.983 (0.973,0.990) | 0.166 (0.144,0.191) | 7.433 (6.072,9.262) | 0.201 (0.118,0.304) |
| Nigeria ZRC PHC | 0.219 (0.191,0.248) | 0.5271 (0.4894,0.5647) | 0.809 (0.744,0.873) | 0.885 (0.857,0.911) | 0.664 (0.595,0.728) | 0.943 (0.922,0.963) | 0.267 (0.236,0.300) | 7.051 (5.619,9.080) | 0.215 (0.144,0.289) |
| Kenya PHC | 0.084 (0.066,0.106) | 0.6086 (0.5713,0.6449) | 0.822 (0.717,0.904) | 0.879 (0.850,0.903) | 0.382 (0.303,0.467) | 0.982 (0.969,0.990) | 0.180 (0.153,0.212) | 6.730 (5.317,8.514) | 0.202 (0.109,0.320) |
| Bangladesh PHC | 0.034 (0.024,0.046) | 0.65 (0.6195,0.6796) | 0.839 (0.668,0.919) | 0.917 (0.897,0.933) | 0.258 (0.184,0.345) | 0.994 (0.986,0.997) | 0.109 (0.090,0.129) | 9.943 (7.400,12.699) | 0.176 (0.088,0.363) |
| Brazil Aracaju PHC | 0.148 (0.120,0.180) | 0.568 (0.5233,0.6119) | 0.839 (0.748,0.919) | 0.913 (0.885,0.935) | 0.625 (0.533,0.708) | 0.970 (0.952,0.985) | 0.199 (0.167,0.235) | 9.546 (7.203,12.954) | 0.177 (0.089,0.276) |
| Brazil Maceio PHC | 0.282 (0.246,0.320) | 0.494 (0.4493,0.5387) | 0.771 (0.704,0.835) | 0.886 (0.849,0.916) | 0.726 (0.652,0.792) | 0.908 (0.877,0.934) | 0.300 (0.262,0.341) | 6.724 (5.033,9.298) | 0.258 (0.187,0.337) |
| Malawi PHC | 0.078 (0.064,0.093) | 0.6317 (0.6037,0.659) | 0.808 (0.714,0.881) | 0.918 (0.901,0.933) | 0.454 (0.378,0.528) | 0.983 (0.974,0.990) | 0.138 (0.120,0.158) | 9.891 (7.877,12.234) | 0.209 (0.130,0.309) |
| CXR-CAD --> Pooled Xpert Ultra --> Xpert Ultra | |||||||||
| Pooled PHC | 0.113 (0.105,0.121) | 0.5984 (0.5854,0.6113) | 0.796 (0.765,0.826) | 1.000 (1.000,1.000) | 1.000 (0.996,1.000) | 0.975 (0.970,0.979) | 0.090 (0.082,0.098) | 39413.637 (1924.073,81984.447) | 0.204 (0.174,0.235) |
| Cameroon PHC | 0.079 (0.063,0.097) | 0.617 (0.5861,0.6472) | 0.797 (0.700,0.876) | 1.000 (0.998,1.000) | 0.999 (0.968,1.000) | 0.983 (0.973,0.990) | 0.063 (0.049,0.079) | 7704.805 (344.593,84862.816) | 0.203 (0.124,0.300) |
| Nigeria ZRC PHC | 0.219 (0.191,0.248) | 0.5271 (0.4894,0.5647) | 0.798 (0.731,0.856) | 1.000 (0.996,1.000) | 0.999 (0.983,1.000) | 0.946 (0.926,0.963) | 0.175 (0.148,0.203) | 4747.049 (207.519,83487.703) | 0.202 (0.144,0.269) |
| Kenya PHC | 0.084 (0.066,0.106) | 0.6086 (0.5713,0.6449) | 0.711 (0.590,0.816) | 1.000 (0.997,1.000) | 0.998 (0.952,1.000) | 0.974 (0.960,0.984) | 0.060 (0.044,0.078) | 4761.034 (224.508,77673.315) | 0.289 (0.184,0.410) |
| Bangladesh PHC | 0.034 (0.024,0.046) | 0.65 (0.6195,0.6796) | 0.824 (0.671,0.925) | 1.000 (0.998,1.000) | 0.997 (0.931,1.000) | 0.994 (0.988,0.998) | 0.028 (0.019,0.040) | 8451.806 (409.402,89398.505) | 0.176 (0.075,0.329) |
| Brazil Aracaju PHC | 0.148 (0.120,0.180) | 0.568 (0.5233,0.6119) | 0.851 (0.757,0.920) | 1.000 (0.995,1.000) | 0.998 (0.970,1.000) | 0.975 (0.957,0.987) | 0.126 (0.099,0.158) | 3906.761 (184.764,89167.511) | 0.149 (0.080,0.244) |
| Brazil Maceio PHC | 0.282 (0.246,0.320) | 0.494 (0.4493,0.5387) | 0.788 (0.717,0.849) | 1.000 (0.994,1.000) | 0.999 (0.982,1.000) | 0.923 (0.894,0.946) | 0.222 (0.186,0.260) | 3017.535 (139.195,82297.818) | 0.212 (0.151,0.284) |
| Malawi PHC | 0.078 (0.064,0.093) | 0.6317 (0.6037,0.659) | 0.805 (0.718,0.879) | 1.000 (0.998,1.000) | 0.999 (0.974,1.000) | 0.984 (0.975,0.990) | 0.063 (0.050,0.077) | 9255.064 (428.824,85338.203) | 0.195 (0.121,0.282) |
| CRP --> Pooled Xpert Ultra --> Xpert Ultra | |||||||||
| Pooled PHC | 0.113 (0.105,0.121) | 0.5984 (0.5854,0.6113) | 0.807 (0.775,0.837) | 1.000 (0.999,1.000) | 0.996 (0.988,0.999) | 0.976 (0.972,0.980) | 0.092 (0.084,0.099) | 1991.463 (653.137,11108.643) | 0.193 (0.163,0.225) |
| Cameroon PHC | 0.079 (0.063,0.097) | 0.617 (0.5861,0.6472) | 0.784 (0.689,0.866) | 0.999 (0.995,1.000) | 0.984 (0.932,0.999) | 0.982 (0.972,0.989) | 0.063 (0.049,0.079) | 713.757 (166.638,10148.079) | 0.216 (0.135,0.312) |
| Nigeria ZRC PHC | 0.219 (0.191,0.248) | 0.5271 (0.4894,0.5647) | 0.863 (0.802,0.911) | 1.000 (0.996,1.000) | 0.999 (0.985,1.000) | 0.963 (0.946,0.976) | 0.189 (0.160,0.218) | 4817.195 (231.659,89324.608) | 0.137 (0.089,0.198) |
| Kenya PHC | 0.084 (0.066,0.106) | 0.6086 (0.5713,0.6449) | 0.814 (0.702,0.901) | 0.998 (0.993,1.000) | 0.980 (0.915,0.998) | 0.983 (0.971,0.991) | 0.070 (0.053,0.090) | 510.364 (121.648,6652.565) | 0.186 (0.099,0.298) |
| Bangladesh PHC | 0.034 (0.024,0.046) | 0.65 (0.6195,0.6796) | 0.734 (0.569,0.862) | 1.000 (0.998,1.000) | 0.996 (0.921,1.000) | 0.991 (0.983,0.996) | 0.025 (0.017,0.036) | 7292.735 (346.480,81741.801) | 0.266 (0.138,0.431) |
| Brazil Aracaju PHC | 0.148 (0.120,0.180) | 0.568 (0.5233,0.6119) | 0.770 (0.671,0.856) | 1.000 (0.995,1.000) | 0.998 (0.967,1.000) | 0.962 (0.942,0.977) | 0.114 (0.088,0.144) | 3518.192 (160.019,82272.736) | 0.230 (0.145,0.329) |
| Brazil Maceio PHC | 0.282 (0.246,0.320) | 0.494 (0.4493,0.5387) | 0.787 (0.714,0.851) | 1.000 (0.995,1.000) | 0.999 (0.982,1.000) | 0.923 (0.894,0.947) | 0.222 (0.187,0.260) | 3009.228 (143.008,81987.958) | 0.213 (0.149,0.287) |
| Malawi PHC | 0.078 (0.064,0.093) | 0.6317 (0.6037,0.659) | 0.818 (0.732,0.887) | 1.000 (0.998,1.000) | 0.999 (0.974,1.000) | 0.985 (0.977,0.991) | 0.063 (0.050,0.078) | 9707.980 (450.413,86435.010) | 0.182 (0.113,0.268) |
| Lam --> Poolxpert --> Xpert | |||||||||
| Pooled PHC | 0.113 (0.105,0.121) | 0.5984 (0.5854,0.6113) | 0.739 (0.704,0.773) | 1.000 (1.000,1.000) | 1.000 (0.996,1.000) | 0.968 (0.963,0.972) | 0.084 (0.077,0.091) | 38625.158 (1896.245,76548.431) | 0.261 (0.227,0.296) |
| Cameroon PHC | 0.079 (0.063,0.097) | 0.617 (0.5861,0.6472) | 0.773 (0.674,0.856) | 1.000 (0.998,1.000) | 0.998 (0.968,1.000) | 0.981 (0.971,0.988) | 0.061 (0.047,0.077) | 7644.567 (352.188,82914.367) | 0.227 (0.144,0.327) |
| Nigeria ZRC PHC | 0.219 (0.191,0.248) | 0.5271 (0.4894,0.5647) | 0.718 (0.642,0.784) | 1.000 (0.996,1.000) | 0.999 (0.983,1.000) | 0.927 (0.904,0.947) | 0.157 (0.132,0.185) | 4230.829 (195.769,75870.874) | 0.282 (0.216,0.358) |
| Kenya PHC | 0.084 (0.066,0.106) | 0.6086 (0.5713,0.6449) | 0.763 (0.647,0.857) | 1.000 (0.997,1.000) | 0.998 (0.958,1.000) | 0.979 (0.966,0.988) | 0.064 (0.048,0.084) | 4896.101 (232.411,82356.111) | 0.237 (0.143,0.354) |
| Bangladesh PHC | 0.034 (0.024,0.046) | 0.65 (0.6195,0.6796) | 0.735 (0.574,0.863) | 1.000 (0.998,1.000) | 0.996 (0.922,1.000) | 0.991 (0.984,0.996) | 0.025 (0.016,0.036) | 7537.109 (360.237,82125.272) | 0.265 (0.137,0.427) |
| Brazil Aracaju PHC | 0.148 (0.120,0.180) | 0.568 (0.5233,0.6119) | 0.783 (0.682,0.865) | 1.000 (0.995,1.000) | 0.998 (0.966,1.000) | 0.964 (0.944,0.978) | 0.116 (0.089,0.145) | 3546.177 (167.521,83384.628) | 0.217 (0.135,0.319) |
| Brazil Maceio PHC | 0.282 (0.246,0.320) | 0.494 (0.4493,0.5387) | 0.716 (0.639,0.785) | 1.000 (0.994,1.000) | 0.999 (0.980,1.000) | 0.900 (0.869,0.927) | 0.202 (0.169,0.238) | 2731.295 (124.243,75323.698) | 0.284 (0.215,0.361) |
| Malawi PHC | 0.078 (0.064,0.093) | 0.6317 (0.6037,0.659) | 0.731 (0.635,0.815) | 1.000 (0.998,1.000) | 0.999 (0.969,1.000) | 0.978 (0.968,0.985) | 0.057 (0.044,0.070) | 8500.805 (398.060,78752.181) | 0.269 (0.185,0.365) |
| CXR-CAD | CRP | LAM --> Pooled Xpert Ultra --> Xpert Ultra | |||||||||
| Pooled PHC | 0.113 (0.105,0.121) | 0.5984 (0.5854,0.6113) | 0.902 (0.878,0.924) | 1.000 (0.999,1.000) | 0.997 (0.990,0.999) | 0.988 (0.984,0.990) | 0.102 (0.095,0.110) | 2238.265 (736.732,11938.371) | 0.098 (0.076,0.122) |
| Cameroon PHC | 0.079 (0.063,0.097) | 0.617 (0.5861,0.6472) | 0.923 (0.853,0.969) | 0.999 (0.995,1.000) | 0.986 (0.943,0.999) | 0.994 (0.987,0.997) | 0.074 (0.059,0.091) | 834.441 (196.608,12008.017) | 0.077 (0.031,0.147) |
| Nigeria ZRC PHC | 0.219 (0.191,0.248) | 0.5271 (0.4894,0.5647) | 0.902 (0.848,0.942) | 1.000 (0.996,1.000) | 0.999 (0.985,1.000) | 0.973 (0.958,0.985) | 0.197 (0.168,0.228) | 5310.099 (255.611,92727.695) | 0.098 (0.058,0.152) |
| Kenya PHC | 0.084 (0.066,0.106) | 0.6086 (0.5713,0.6449) | 0.915 (0.827,0.968) | 0.998 (0.993,1.000) | 0.981 (0.923,0.999) | 0.992 (0.983,0.997) | 0.079 (0.060,0.100) | 568.844 (134.685,7465.776) | 0.085 (0.032,0.173) |
| Bangladesh PHC | 0.034 (0.024,0.046) | 0.65 (0.6195,0.6796) | 0.822 (0.673,0.925) | 1.000 (0.998,1.000) | 0.997 (0.933,1.000) | 0.994 (0.987,0.998) | 0.028 (0.019,0.039) | 8672.711 (416.920,89626.012) | 0.178 (0.075,0.327) |
| Brazil Aracaju PHC | 0.148 (0.120,0.180) | 0.568 (0.5233,0.6119) | 0.905 (0.825,0.958) | 1.000 (0.995,1.000) | 0.999 (0.970,1.000) | 0.984 (0.969,0.993) | 0.134 (0.107,0.166) | 4182.208 (194.105,93776.415) | 0.095 (0.042,0.176) |
| Brazil Maceio PHC | 0.282 (0.246,0.320) | 0.494 (0.4493,0.5387) | 0.908 (0.853,0.948) | 1.000 (0.994,1.000) | 0.999 (0.984,1.000) | 0.965 (0.943,0.981) | 0.257 (0.220,0.295) | 3501.553 (159.720,93151.845) | 0.092 (0.052,0.147) |
| Malawi PHC | 0.078 (0.064,0.093) | 0.6317 (0.6037,0.659) | 0.892 (0.820,0.945) | 1.000 (0.998,1.000) | 0.999 (0.976,1.000) | 0.991 (0.984,0.996) | 0.069 (0.056,0.084) | 9774.957 (478.220,92914.770) | 0.108 (0.055,0.180) |
| CXR-CAD | LAM --> Pooled Xpert Ultra --> Xpert Ultra | |||||||||
| Pooled PHC | 0.113 (0.105,0.121) | 0.5984 (0.5854,0.6113) | 0.883 (0.857,0.907) | 1.000 (1.000,1.000) | 1.000 (0.996,1.000) | 0.985 (0.982,0.988) | 0.100 (0.092,0.108) | 45487.136 (2224.970,90155.790) | 0.117 (0.093,0.143) |
| Cameroon PHC | 0.079 (0.063,0.097) | 0.617 (0.5861,0.6472) | 0.899 (0.822,0.952) | 1.000 (0.998,1.000) | 0.999 (0.972,1.000) | 0.991 (0.984,0.996) | 0.071 (0.056,0.088) | 8608.933 (420.889,93476.745) | 0.101 (0.048,0.178) |
| Nigeria ZRC PHC | 0.219 (0.191,0.248) | 0.5271 (0.4894,0.5647) | 0.882 (0.825,0.927) | 1.000 (0.996,1.000) | 0.999 (0.986,1.000) | 0.968 (0.952,0.981) | 0.193 (0.164,0.223) | 4944.184 (238.498,90938.689) | 0.118 (0.073,0.175) |
| Kenya PHC | 0.084 (0.066,0.106) | 0.6086 (0.5713,0.6449) | 0.899 (0.803,0.958) | 1.000 (0.997,1.000) | 0.998 (0.964,1.000) | 0.991 (0.982,0.996) | 0.076 (0.058,0.097) | 6029.688 (277.106,93685.533) | 0.101 (0.042,0.197) |
| Bangladesh PHC | 0.034 (0.024,0.046) | 0.65 (0.6195,0.6796) | 0.825 (0.675,0.925) | 1.000 (0.998,1.000) | 0.997 (0.933,1.000) | 0.994 (0.988,0.998) | 0.028 (0.019,0.040) | 8270.502 (383.749,89666.960) | 0.175 (0.075,0.325) |
| Brazil Aracaju PHC | 0.148 (0.120,0.180) | 0.568 (0.5233,0.6119) | 0.906 (0.827,0.958) | 1.000 (0.995,1.000) | 0.999 (0.971,1.000) | 0.984 (0.969,0.993) | 0.134 (0.106,0.166) | 4052.374 (190.165,93808.578) | 0.094 (0.042,0.173) |
| Brazil Maceio PHC | 0.282 (0.246,0.320) | 0.494 (0.4493,0.5387) | 0.887 (0.826,0.932) | 1.000 (0.994,1.000) | 0.999 (0.984,1.000) | 0.957 (0.934,0.975) | 0.250 (0.214,0.288) | 3258.125 (149.013,91349.794) | 0.114 (0.068,0.174) |
| Malawi PHC | 0.078 (0.064,0.093) | 0.6317 (0.6037,0.659) | 0.860 (0.781,0.920) | 1.000 (0.998,1.000) | 0.999 (0.976,1.000) | 0.988 (0.981,0.994) | 0.067 (0.054,0.082) | 10146.025 (447.336,90072.318) | 0.140 (0.080,0.219) |
| CRP | LAM --> Pooled Xpert Ultra --> Xpert Ultra | |||||||||
| Pooled PHC | 0.113 (0.105,0.121) | 0.5984 (0.5854,0.6113) | 0.891 (0.865,0.914) | 1.000 (0.999,1.000) | 0.996 (0.989,0.999) | 0.986 (0.983,0.989) | 0.101 (0.093,0.109) | 2230.336 (724.281,13248.388) | 0.109 (0.086,0.135) |
| Cameroon PHC | 0.079 (0.063,0.097) | 0.617 (0.5861,0.6472) | 0.898 (0.819,0.953) | 0.999 (0.995,1.000) | 0.986 (0.940,0.999) | 0.991 (0.984,0.996) | 0.072 (0.057,0.089) | 820.169 (190.598,11395.870) | 0.102 (0.047,0.182) |
| Nigeria ZRC PHC | 0.219 (0.191,0.248) | 0.5271 (0.4894,0.5647) | 0.895 (0.840,0.937) | 1.000 (0.996,1.000) | 0.999 (0.986,1.000) | 0.971 (0.956,0.983) | 0.196 (0.168,0.227) | 5306.173 (241.689,92150.175) | 0.105 (0.063,0.160) |
| Kenya PHC | 0.084 (0.066,0.106) | 0.6086 (0.5713,0.6449) | 0.915 (0.829,0.968) | 0.998 (0.993,1.000) | 0.982 (0.923,0.999) | 0.992 (0.984,0.997) | 0.079 (0.060,0.100) | 560.744 (133.166,7089.151) | 0.085 (0.032,0.171) |
| Bangladesh PHC | 0.034 (0.024,0.046) | 0.65 (0.6195,0.6796) | 0.792 (0.638,0.904) | 1.000 (0.998,1.000) | 0.996 (0.929,1.000) | 0.993 (0.986,0.997) | 0.027 (0.018,0.038) | 8246.406 (370.679,87208.427) | 0.208 (0.096,0.362) |
| Brazil Aracaju PHC | 0.148 (0.120,0.180) | 0.568 (0.5233,0.6119) | 0.905 (0.826,0.959) | 1.000 (0.995,1.000) | 0.999 (0.971,1.000) | 0.984 (0.969,0.993) | 0.134 (0.106,0.167) | 4316.913 (186.624,93860.781) | 0.095 (0.041,0.174) |
| Brazil Maceio PHC | 0.282 (0.246,0.320) | 0.494 (0.4493,0.5387) | 0.894 (0.836,0.938) | 1.000 (0.994,1.000) | 0.999 (0.984,1.000) | 0.960 (0.936,0.977) | 0.252 (0.216,0.291) | 3252.491 (158.347,91808.824) | 0.107 (0.063,0.164) |
| Malawi PHC | 0.078 (0.064,0.093) | 0.6317 (0.6037,0.659) | 0.883 (0.806,0.937) | 1.000 (0.998,1.000) | 0.999 (0.976,1.000) | 0.990 (0.983,0.995) | 0.068 (0.055,0.084) | 10572.058 (506.021,91822.910) | 0.117 (0.063,0.194) |
| CXR-CAD | CRP --> Pooled Xpert Ultra --> Xpert Ultra | |||||||||
| Pooled PHC | 0.113 (0.105,0.121) | 0.5984 (0.5854,0.6113) | 0.885 (0.858,0.909) | 1.000 (0.999,1.000) | 0.996 (0.989,0.999) | 0.986 (0.982,0.989) | 0.100 (0.093,0.108) | 2169.317 (726.623,12328.004) | 0.115 (0.091,0.142) |
| Cameroon PHC | 0.079 (0.063,0.097) | 0.617 (0.5861,0.6472) | 0.886 (0.803,0.943) | 0.999 (0.995,1.000) | 0.986 (0.940,0.999) | 0.990 (0.983,0.995) | 0.071 (0.056,0.088) | 802.685 (191.984,11436.669) | 0.114 (0.057,0.197) |
| Nigeria ZRC PHC | 0.219 (0.191,0.248) | 0.5271 (0.4894,0.5647) | 0.902 (0.850,0.943) | 1.000 (0.996,1.000) | 0.999 (0.986,1.000) | 0.973 (0.958,0.984) | 0.197 (0.168,0.228) | 5205.219 (249.300,92749.310) | 0.098 (0.057,0.150) |
| Kenya PHC | 0.084 (0.066,0.106) | 0.6086 (0.5713,0.6449) | 0.880 (0.785,0.947) | 0.998 (0.993,1.000) | 0.981 (0.919,0.999) | 0.989 (0.979,0.995) | 0.076 (0.058,0.097) | 553.769 (129.824,7515.063) | 0.120 (0.054,0.216) |
| Bangladesh PHC | 0.034 (0.024,0.046) | 0.65 (0.6195,0.6796) | 0.824 (0.677,0.924) | 1.000 (0.998,1.000) | 0.996 (0.928,1.000) | 0.994 (0.988,0.998) | 0.028 (0.019,0.040) | 8487.603 (393.002,89366.693) | 0.176 (0.076,0.323) |
| Brazil Aracaju PHC | 0.148 (0.120,0.180) | 0.568 (0.5233,0.6119) | 0.891 (0.807,0.949) | 1.000 (0.995,1.000) | 0.999 (0.970,1.000) | 0.982 (0.966,0.991) | 0.132 (0.104,0.163) | 3743.796 (187.704,92527.915) | 0.109 (0.051,0.193) |
| Brazil Maceio PHC | 0.282 (0.246,0.320) | 0.494 (0.4493,0.5387) | 0.887 (0.827,0.932) | 1.000 (0.994,1.000) | 0.999 (0.984,1.000) | 0.958 (0.933,0.975) | 0.250 (0.214,0.291) | 3326.905 (156.066,91440.199) | 0.114 (0.068,0.173) |
| Malawi PHC | 0.078 (0.064,0.093) | 0.6317 (0.6037,0.659) | 0.871 (0.790,0.930) | 1.000 (0.998,1.000) | 0.999 (0.976,1.000) | 0.989 (0.982,0.994) | 0.067 (0.054,0.082) | 9644.180 (471.741,91258.989) | 0.129 (0.071,0.210) |
| CXR-CAD --> Xpert Ultra | |||||||||
| Pooled PHC | 0.113 (0.105,0.121) | 0.5984 (0.5854,0.6113) | 0.867 (0.839,0.892) | 0.999 (0.998,1.000) | 0.991 (0.981,0.997) | 0.983 (0.980,0.987) | 0.099 (0.091,0.107) | 860.462 (401.401,2454.170) | 0.133 (0.108,0.161) |
| Cameroon PHC | 0.079 (0.063,0.097) | 0.617 (0.5861,0.6472) | 0.849 (0.760,0.916) | 0.999 (0.995,1.000) | 0.985 (0.939,0.999) | 0.987 (0.978,0.993) | 0.068 (0.053,0.085) | 773.244 (177.759,10763.883) | 0.151 (0.084,0.241) |
| Nigeria ZRC PHC | 0.219 (0.191,0.248) | 0.5271 (0.4894,0.5647) | 0.863 (0.802,0.911) | 0.998 (0.992,1.000) | 0.992 (0.968,0.999) | 0.963 (0.946,0.976) | 0.190 (0.162,0.220) | 469.351 (111.563,6639.232) | 0.138 (0.089,0.199) |
| Kenya PHC | 0.084 (0.066,0.106) | 0.6086 (0.5713,0.6449) | 0.797 (0.683,0.885) | 1.000 (0.997,1.000) | 0.998 (0.959,1.000) | 0.982 (0.969,0.990) | 0.067 (0.050,0.087) | 5404.591 (268.770,85541.016) | 0.203 (0.115,0.317) |
| Bangladesh PHC | 0.034 (0.024,0.046) | 0.65 (0.6195,0.6796) | 0.970 (0.874,0.998) | 0.999 (0.995,1.000) | 0.970 (0.880,0.998) | 0.999 (0.995,1.000) | 0.034 (0.024,0.046) | 911.740 (204.915,11735.080) | 0.030 (0.002,0.126) |
| Brazil Aracaju PHC | 0.148 (0.120,0.180) | 0.568 (0.5233,0.6119) | 0.905 (0.822,0.958) | 1.000 (0.995,1.000) | 0.999 (0.971,1.000) | 0.984 (0.970,0.993) | 0.134 (0.106,0.165) | 4230.311 (189.645,93645.573) | 0.095 (0.042,0.178) |
| Brazil Maceio PHC | 0.282 (0.246,0.320) | 0.494 (0.4493,0.5387) | 0.851 (0.788,0.903) | 1.000 (0.994,1.000) | 0.999 (0.984,1.000) | 0.945 (0.919,0.964) | 0.240 (0.203,0.278) | 3168.237 (150.611,88162.783) | 0.149 (0.097,0.212) |
| Malawi PHC | 0.078 (0.064,0.093) | 0.6317 (0.6037,0.659) | 0.892 (0.820,0.945) | 0.998 (0.995,1.000) | 0.976 (0.928,0.996) | 0.991 (0.984,0.995) | 0.071 (0.057,0.086) | 494.578 (164.943,2794.175) | 0.108 (0.055,0.180) |
| CRP --> Xpert Ultra | |||||||||
| Pooled PHC | 0.113 (0.105,0.121) | 0.5984 (0.5854,0.6113) | 0.880 (0.853,0.904) | 0.999 (0.998,1.000) | 0.991 (0.981,0.997) | 0.985 (0.981,0.988) | 0.100 (0.092,0.108) | 863.952 (402.222,2455.879) | 0.120 (0.097,0.147) |
| Cameroon PHC | 0.079 (0.063,0.097) | 0.617 (0.5861,0.6472) | 0.836 (0.744,0.906) | 0.999 (0.995,1.000) | 0.985 (0.935,0.999) | 0.986 (0.977,0.992) | 0.067 (0.053,0.084) | 768.142 (176.368,11053.482) | 0.164 (0.094,0.256) |
| Nigeria ZRC PHC | 0.219 (0.191,0.248) | 0.5271 (0.4894,0.5647) | 0.929 (0.881,0.962) | 0.998 (0.992,1.000) | 0.993 (0.970,1.000) | 0.980 (0.966,0.990) | 0.204 (0.176,0.235) | 501.526 (119.126,6979.178) | 0.072 (0.038,0.119) |
| Kenya PHC | 0.084 (0.066,0.106) | 0.6086 (0.5713,0.6449) | 0.899 (0.801,0.958) | 0.997 (0.990,0.999) | 0.963 (0.890,0.994) | 0.991 (0.981,0.996) | 0.078 (0.060,0.100) | 290.838 (91.692,1704.813) | 0.102 (0.042,0.200) |
| Bangladesh PHC | 0.034 (0.024,0.046) | 0.65 (0.6195,0.6796) | 0.882 (0.747,0.963) | 1.000 (0.998,1.000) | 0.997 (0.937,1.000) | 0.996 (0.990,0.999) | 0.030 (0.020,0.042) | 8690.725 (409.575,93936.819) | 0.118 (0.037,0.253) |
| Brazil Aracaju PHC | 0.148 (0.120,0.180) | 0.568 (0.5233,0.6119) | 0.824 (0.729,0.898) | 1.000 (0.995,1.000) | 0.998 (0.969,1.000) | 0.970 (0.952,0.983) | 0.121 (0.095,0.152) | 3981.515 (176.383,86882.586) | 0.176 (0.102,0.272) |
| Brazil Maceio PHC | 0.282 (0.246,0.320) | 0.494 (0.4493,0.5387) | 0.858 (0.796,0.910) | 0.997 (0.988,1.000) | 0.992 (0.965,0.999) | 0.947 (0.921,0.967) | 0.244 (0.209,0.283) | 299.030 (70.956,4314.863) | 0.143 (0.090,0.205) |
| Malawi PHC | 0.078 (0.064,0.093) | 0.6317 (0.6037,0.659) | 0.903 (0.833,0.951) | 1.000 (0.998,1.000) | 0.999 (0.976,1.000) | 0.992 (0.986,0.996) | 0.070 (0.056,0.086) | 10545.636 (490.995,93581.947) | 0.097 (0.049,0.167) |
| LAM --> Xpert Ultra | |||||||||
| Pooled PHC | 0.113 (0.105,0.121) | 0.5984 (0.5854,0.6113) | 0.794 (0.761,0.825) | 0.999 (0.998,1.000) | 0.988 (0.977,0.995) | 0.974 (0.970,0.978) | 0.091 (0.084,0.098) | 656.614 (319.564,1686.898) | 0.206 (0.175,0.239) |
| Cameroon PHC | 0.079 (0.063,0.097) | 0.617 (0.5861,0.6472) | 0.811 (0.715,0.886) | 0.999 (0.995,1.000) | 0.984 (0.935,0.999) | 0.984 (0.975,0.991) | 0.065 (0.051,0.081) | 725.151 (171.527,9381.243) | 0.189 (0.114,0.285) |
| Nigeria ZRC PHC | 0.219 (0.191,0.248) | 0.5271 (0.4894,0.5647) | 0.778 (0.709,0.839) | 0.998 (0.992,1.000) | 0.992 (0.964,0.999) | 0.942 (0.920,0.959) | 0.172 (0.144,0.201) | 419.907 (96.547,6088.426) | 0.223 (0.161,0.292) |
| Kenya PHC | 0.084 (0.066,0.106) | 0.6086 (0.5713,0.6449) | 0.814 (0.698,0.899) | 0.997 (0.990,0.999) | 0.960 (0.882,0.993) | 0.983 (0.972,0.991) | 0.071 (0.054,0.092) | 255.349 (82.163,1461.983) | 0.187 (0.102,0.303) |
| Bangladesh PHC | 0.034 (0.024,0.046) | 0.65 (0.6195,0.6796) | 0.823 (0.674,0.925) | 1.000 (0.998,1.000) | 0.997 (0.926,1.000) | 0.994 (0.987,0.997) | 0.028 (0.019,0.039) | 8356.939 (387.825,89576.892) | 0.177 (0.075,0.326) |
| Brazil Aracaju PHC | 0.148 (0.120,0.180) | 0.568 (0.5233,0.6119) | 0.825 (0.727,0.899) | 1.000 (0.995,1.000) | 0.998 (0.969,1.000) | 0.970 (0.952,0.984) | 0.122 (0.095,0.153) | 3742.073 (172.023,86765.348) | 0.175 (0.101,0.273) |
| Brazil Maceio PHC | 0.282 (0.246,0.320) | 0.494 (0.4493,0.5387) | 0.767 (0.694,0.831) | 1.000 (0.994,1.000) | 0.999 (0.981,1.000) | 0.916 (0.886,0.940) | 0.216 (0.182,0.253) | 3026.694 (135.509,80049.463) | 0.233 (0.169,0.306) |
| Malawi PHC | 0.078 (0.064,0.093) | 0.6317 (0.6037,0.659) | 0.805 (0.718,0.878) | 0.998 (0.995,1.000) | 0.974 (0.923,0.995) | 0.984 (0.976,0.990) | 0.064 (0.051,0.079) | 438.919 (146.666,2511.679) | 0.195 (0.122,0.283) |
| CXR-CAD | CRP | LAM --> Xpert Ultra | |||||||||
| Pooled PHC | 0.113 (0.105,0.121) | 0.5984 (0.5854,0.6113) | 0.979 (0.966,0.988) | 0.997 (0.996,0.999) | 0.980 (0.966,0.989) | 0.997 (0.996,0.999) | 0.113 (0.105,0.122) | 373.603 (226.308,679.422) | 0.021 (0.012,0.034) |
| Cameroon PHC | 0.079 (0.063,0.097) | 0.617 (0.5861,0.6472) | 0.974 (0.923,0.995) | 0.998 (0.994,1.000) | 0.975 (0.925,0.995) | 0.998 (0.993,1.000) | 0.079 (0.063,0.096) | 448.842 (149.766,2527.941) | 0.026 (0.005,0.077) |
| Nigeria ZRC PHC | 0.219 (0.191,0.248) | 0.5271 (0.4894,0.5647) | 0.967 (0.932,0.988) | 0.995 (0.986,0.999) | 0.980 (0.949,0.995) | 0.991 (0.981,0.997) | 0.216 (0.186,0.247) | 176.722 (68.275,712.663) | 0.033 (0.012,0.069) |
| Kenya PHC | 0.084 (0.066,0.106) | 0.6086 (0.5713,0.6449) | 0.998 (0.966,1.000) | 0.995 (0.988,0.999) | 0.951 (0.879,0.988) | 1.000 (0.997,1.000) | 0.089 (0.070,0.112) | 211.882 (84.094,810.756) | 0.002 (0.000,0.034) |
| Bangladesh PHC | 0.034 (0.024,0.046) | 0.65 (0.6195,0.6796) | 0.970 (0.877,0.998) | 0.999 (0.996,1.000) | 0.970 (0.876,0.998) | 0.999 (0.995,1.000) | 0.034 (0.024,0.047) | 901.642 (211.801,12397.270) | 0.030 (0.002,0.123) |
| Brazil Aracaju PHC | 0.148 (0.120,0.180) | 0.568 (0.5233,0.6119) | 0.973 (0.920,0.995) | 1.000 (0.995,1.000) | 0.999 (0.973,1.000) | 0.995 (0.986,0.999) | 0.144 (0.116,0.177) | 3955.813 (205.672,98794.190) | 0.027 (0.005,0.080) |
| Brazil Maceio PHC | 0.282 (0.246,0.320) | 0.494 (0.4493,0.5387) | 0.986 (0.958,0.997) | 0.997 (0.988,1.000) | 0.993 (0.969,0.999) | 0.994 (0.983,0.999) | 0.280 (0.242,0.321) | 340.558 (81.839,4873.546) | 0.014 (0.003,0.042) |
| Malawi PHC | 0.078 (0.064,0.093) | 0.6317 (0.6037,0.659) | 0.989 (0.954,0.999) | 0.997 (0.993,0.999) | 0.969 (0.921,0.992) | 0.999 (0.996,1.000) | 0.079 (0.065,0.095) | 361.380 (141.446,1443.434) | 0.011 (0.001,0.046) |
| CXR-CAD | LAM --> Xpert Ultra | |||||||||
| Pooled PHC | 0.113 (0.105,0.121) | 0.5984 (0.5854,0.6113) | 0.957 (0.940,0.971) | 0.998 (0.997,0.999) | 0.985 (0.974,0.993) | 0.995 (0.992,0.996) | 0.110 (0.102,0.118) | 529.452 (293.110,1095.624) | 0.043 (0.029,0.060) |
| Cameroon PHC | 0.079 (0.063,0.097) | 0.617 (0.5861,0.6472) | 0.950 (0.889,0.983) | 0.999 (0.995,1.000) | 0.987 (0.944,0.999) | 0.996 (0.990,0.999) | 0.076 (0.061,0.094) | 853.619 (198.208,11989.482) | 0.050 (0.017,0.112) |
| Nigeria ZRC PHC | 0.219 (0.191,0.248) | 0.5271 (0.4894,0.5647) | 0.948 (0.906,0.975) | 0.996 (0.989,0.999) | 0.986 (0.959,0.998) | 0.986 (0.973,0.993) | 0.210 (0.180,0.242) | 255.786 (83.498,1347.608) | 0.053 (0.025,0.094) |
| Kenya PHC | 0.084 (0.066,0.106) | 0.6086 (0.5713,0.6449) | 0.983 (0.929,0.999) | 0.997 (0.990,0.999) | 0.966 (0.902,0.994) | 0.998 (0.993,1.000) | 0.086 (0.067,0.108) | 313.444 (102.684,1806.551) | 0.017 (0.001,0.071) |
| Bangladesh PHC | 0.034 (0.024,0.046) | 0.65 (0.6195,0.6796) | 0.970 (0.881,0.998) | 0.999 (0.995,1.000) | 0.970 (0.884,0.998) | 0.999 (0.995,1.000) | 0.034 (0.024,0.047) | 890.031 (212.137,11993.847) | 0.030 (0.002,0.119) |
| Brazil Aracaju PHC | 0.148 (0.120,0.180) | 0.568 (0.5233,0.6119) | 0.973 (0.919,0.995) | 1.000 (0.995,1.000) | 0.999 (0.973,1.000) | 0.995 (0.986,0.999) | 0.144 (0.115,0.177) | 4316.675 (201.188,98861.969) | 0.027 (0.005,0.081) |
| Brazil Maceio PHC | 0.282 (0.246,0.320) | 0.494 (0.4493,0.5387) | 0.957 (0.916,0.983) | 1.000 (0.994,1.000) | 0.999 (0.985,1.000) | 0.983 (0.967,0.993) | 0.270 (0.234,0.311) | 3685.842 (171.756,97223.973) | 0.043 (0.017,0.084) |
| Malawi PHC | 0.078 (0.064,0.093) | 0.6317 (0.6037,0.659) | 0.947 (0.888,0.980) | 0.997 (0.993,0.999) | 0.966 (0.917,0.991) | 0.996 (0.990,0.998) | 0.076 (0.062,0.092) | 349.166 (135.280,1342.840) | 0.054 (0.020,0.112) |
| CRP | LAM --> Xpert Ultra | |||||||||
| Pooled PHC | 0.113 (0.105,0.121) | 0.5984 (0.5854,0.6113) | 0.968 (0.953,0.980) | 0.998 (0.997,0.999) | 0.984 (0.972,0.992) | 0.996 (0.994,0.998) | 0.111 (0.103,0.120) | 485.302 (277.180,956.954) | 0.032 (0.020,0.047) |
| Cameroon PHC | 0.079 (0.063,0.097) | 0.617 (0.5861,0.6472) | 0.949 (0.888,0.984) | 0.998 (0.993,1.000) | 0.974 (0.923,0.995) | 0.996 (0.990,0.999) | 0.077 (0.061,0.095) | 427.442 (141.828,2425.785) | 0.051 (0.016,0.113) |
| Nigeria ZRC PHC | 0.219 (0.191,0.248) | 0.5271 (0.4894,0.5647) | 0.961 (0.921,0.984) | 0.996 (0.989,0.999) | 0.986 (0.960,0.998) | 0.989 (0.978,0.996) | 0.213 (0.184,0.244) | 263.878 (87.415,1605.845) | 0.039 (0.016,0.079) |
| Kenya PHC | 0.084 (0.066,0.106) | 0.6086 (0.5713,0.6449) | 0.998 (0.966,1.000) | 0.995 (0.988,0.999) | 0.952 (0.881,0.987) | 1.000 (0.997,1.000) | 0.089 (0.069,0.111) | 211.524 (81.368,833.096) | 0.002 (0.000,0.034) |
| Bangladesh PHC | 0.034 (0.024,0.046) | 0.65 (0.6195,0.6796) | 0.941 (0.833,0.989) | 1.000 (0.998,1.000) | 0.997 (0.939,1.000) | 0.998 (0.994,1.000) | 0.032 (0.022,0.044) | 9273.873 (447.717,97932.963) | 0.059 (0.011,0.167) |
| Brazil Aracaju PHC | 0.148 (0.120,0.180) | 0.568 (0.5233,0.6119) | 0.973 (0.921,0.995) | 1.000 (0.995,1.000) | 0.999 (0.972,1.000) | 0.995 (0.986,0.999) | 0.144 (0.115,0.176) | 4149.298 (206.227,98880.384) | 0.027 (0.005,0.079) |
| Brazil Maceio PHC | 0.282 (0.246,0.320) | 0.494 (0.4493,0.5387) | 0.972 (0.935,0.991) | 0.997 (0.988,1.000) | 0.993 (0.969,0.999) | 0.989 (0.975,0.996) | 0.276 (0.238,0.316) | 341.210 (78.255,4475.841) | 0.028 (0.009,0.065) |
| Malawi PHC | 0.078 (0.064,0.093) | 0.6317 (0.6037,0.659) | 0.979 (0.937,0.996) | 0.998 (0.994,1.000) | 0.978 (0.936,0.996) | 0.998 (0.995,1.000) | 0.078 (0.063,0.093) | 536.179 (174.661,2908.212) | 0.021 (0.004,0.063) |
| CXR-CAD | CRP --> Xpert Ultra | |||||||||
| Pooled PHC | 0.113 (0.105,0.121) | 0.5984 (0.5854,0.6113) | 0.962 (0.946,0.975) | 0.998 (0.996,0.999) | 0.984 (0.972,0.992) | 0.995 (0.993,0.997) | 0.111 (0.103,0.119) | 479.779 (272.476,955.915) | 0.038 (0.025,0.054) |
| Cameroon PHC | 0.079 (0.063,0.097) | 0.617 (0.5861,0.6472) | 0.937 (0.869,0.977) | 0.998 (0.993,1.000) | 0.974 (0.921,0.995) | 0.995 (0.988,0.998) | 0.076 (0.061,0.093) | 431.824 (140.916,2476.638) | 0.064 (0.023,0.131) |
| Nigeria ZRC PHC | 0.219 (0.191,0.248) | 0.5271 (0.4894,0.5647) | 0.967 (0.931,0.988) | 0.996 (0.989,0.999) | 0.987 (0.960,0.998) | 0.991 (0.981,0.997) | 0.214 (0.185,0.247) | 263.814 (84.537,1495.317) | 0.033 (0.012,0.069) |
| Kenya PHC | 0.084 (0.066,0.106) | 0.6086 (0.5713,0.6449) | 0.966 (0.900,0.994) | 0.997 (0.990,0.999) | 0.966 (0.901,0.994) | 0.997 (0.990,0.999) | 0.084 (0.065,0.106) | 308.394 (99.418,1780.220) | 0.034 (0.006,0.101) |
| Bangladesh PHC | 0.034 (0.024,0.046) | 0.65 (0.6195,0.6796) | 0.971 (0.878,0.998) | 0.999 (0.995,1.000) | 0.970 (0.877,0.998) | 0.999 (0.995,1.000) | 0.034 (0.024,0.047) | 894.373 (206.237,13187.341) | 0.029 (0.002,0.123) |
| Brazil Aracaju PHC | 0.148 (0.120,0.180) | 0.568 (0.5233,0.6119) | 0.960 (0.898,0.989) | 1.000 (0.995,1.000) | 0.999 (0.972,1.000) | 0.993 (0.982,0.998) | 0.142 (0.113,0.173) | 4263.644 (199.075,97913.651) | 0.040 (0.011,0.102) |
| Brazil Maceio PHC | 0.282 (0.246,0.320) | 0.494 (0.4493,0.5387) | 0.964 (0.926,0.987) | 0.997 (0.988,1.000) | 0.993 (0.967,0.999) | 0.986 (0.971,0.995) | 0.274 (0.236,0.313) | 336.646 (79.940,4472.591) | 0.036 (0.013,0.074) |
| Malawi PHC | 0.078 (0.064,0.093) | 0.6317 (0.6037,0.659) | 0.968 (0.918,0.992) | 0.998 (0.994,1.000) | 0.978 (0.935,0.996) | 0.997 (0.993,0.999) | 0.077 (0.062,0.093) | 529.881 (172.453,2963.338) | 0.032 (0.008,0.082) |
| CXR-CAD --> LAM | |||||||||
| Pooled PHC | 0.113 (0.105,0.121) | 0.5984 (0.5854,0.6113) | 0.717 (0.681,0.751) | 0.989 (0.986,0.991) | 0.890 (0.861,0.915) | 0.965 (0.960,0.970) | 0.091 (0.083,0.099) | 63.459 (49.349,84.067) | 0.286 (0.252,0.322) |
| Cameroon PHC | 0.079 (0.063,0.097) | 0.617 (0.5861,0.6472) | 0.721 (0.616,0.813) | 0.984 (0.974,0.990) | 0.791 (0.690,0.874) | 0.976 (0.965,0.985) | 0.072 (0.057,0.089) | 44.149 (27.459,76.110) | 0.284 (0.190,0.390) |
| Nigeria ZRC PHC | 0.219 (0.191,0.248) | 0.5271 (0.4894,0.5647) | 0.720 (0.644,0.787) | 0.985 (0.973,0.993) | 0.932 (0.878,0.969) | 0.926 (0.903,0.945) | 0.168 (0.142,0.197) | 49.177 (26.547,108.327) | 0.285 (0.216,0.361) |
| Kenya PHC | 0.084 (0.066,0.106) | 0.6086 (0.5713,0.6449) | 0.626 (0.501,0.744) | 0.984 (0.972,0.992) | 0.787 (0.656,0.887) | 0.966 (0.951,0.979) | 0.067 (0.050,0.088) | 40.029 (21.726,82.459) | 0.380 (0.261,0.506) |
| Bangladesh PHC | 0.034 (0.024,0.046) | 0.65 (0.6195,0.6796) | 0.824 (0.677,0.926) | 0.996 (0.990,0.999) | 0.876 (0.735,0.958) | 0.994 (0.988,0.998) | 0.032 (0.022,0.044) | 196.758 (83.322,627.520) | 0.176 (0.074,0.325) |
| Brazil Aracaju PHC | 0.148 (0.120,0.180) | 0.568 (0.5233,0.6119) | 0.771 (0.666,0.855) | 0.991 (0.979,0.997) | 0.934 (0.854,0.979) | 0.961 (0.941,0.977) | 0.122 (0.095,0.153) | 82.234 (35.039,259.976) | 0.232 (0.146,0.337) |
| Brazil Maceio PHC | 0.282 (0.246,0.320) | 0.494 (0.4493,0.5387) | 0.666 (0.588,0.741) | 0.983 (0.967,0.993) | 0.940 (0.883,0.975) | 0.882 (0.848,0.912) | 0.200 (0.167,0.236) | 39.694 (20.018,98.301) | 0.340 (0.264,0.420) |
| Malawi PHC | 0.078 (0.064,0.093) | 0.6317 (0.6037,0.659) | 0.764 (0.671,0.842) | 0.992 (0.986,0.996) | 0.887 (0.807,0.944) | 0.980 (0.971,0.987) | 0.067 (0.053,0.082) | 93.995 (51.805,195.248) | 0.238 (0.159,0.332) |
| CRP --> LAM | |||||||||
| Pooled PHC | 0.113 (0.105,0.121) | 0.5984 (0.5854,0.6113) | 0.719 (0.683,0.753) | 0.996 (0.993,0.997) | 0.954 (0.933,0.970) | 0.965 (0.960,0.970) | 0.085 (0.078,0.093) | 162.676 (110.343,253.192) | 0.282 (0.248,0.319) |
| Cameroon PHC | 0.079 (0.063,0.097) | 0.617 (0.5861,0.6472) | 0.709 (0.603,0.800) | 0.991 (0.984,0.996) | 0.876 (0.780,0.940) | 0.975 (0.964,0.984) | 0.064 (0.050,0.080) | 80.448 (43.189,174.997) | 0.294 (0.202,0.401) |
| Nigeria ZRC PHC | 0.219 (0.191,0.248) | 0.5271 (0.4894,0.5647) | 0.777 (0.708,0.838) | 1.000 (0.996,1.000) | 0.999 (0.983,1.000) | 0.941 (0.920,0.959) | 0.170 (0.143,0.198) | 4561.184 (216.997,81596.094) | 0.223 (0.162,0.293) |
| Kenya PHC | 0.084 (0.066,0.106) | 0.6086 (0.5713,0.6449) | 0.713 (0.591,0.818) | 0.992 (0.984,0.997) | 0.893 (0.787,0.960) | 0.974 (0.960,0.984) | 0.067 (0.050,0.087) | 91.235 (42.565,254.782) | 0.290 (0.184,0.412) |
| Bangladesh PHC | 0.034 (0.024,0.046) | 0.65 (0.6195,0.6796) | 0.763 (0.606,0.885) | 0.996 (0.990,0.999) | 0.868 (0.719,0.958) | 0.992 (0.985,0.996) | 0.030 (0.021,0.042) | 179.698 (76.430,600.739) | 0.238 (0.116,0.395) |
| Brazil Aracaju PHC | 0.148 (0.120,0.180) | 0.568 (0.5233,0.6119) | 0.676 (0.564,0.774) | 1.000 (0.995,1.000) | 0.998 (0.960,1.000) | 0.947 (0.923,0.965) | 0.100 (0.075,0.128) | 3175.741 (144.971,73353.871) | 0.324 (0.226,0.436) |
| Brazil Maceio PHC | 0.282 (0.246,0.320) | 0.494 (0.4493,0.5387) | 0.660 (0.581,0.736) | 0.997 (0.988,1.000) | 0.989 (0.955,0.999) | 0.882 (0.849,0.911) | 0.188 (0.156,0.224) | 239.145 (53.677,3699.328) | 0.341 (0.265,0.420) |
| Malawi PHC | 0.078 (0.064,0.093) | 0.6317 (0.6037,0.659) | 0.742 (0.646,0.822) | 0.996 (0.992,0.999) | 0.946 (0.878,0.983) | 0.979 (0.969,0.986) | 0.061 (0.048,0.075) | 204.301 (88.157,651.008) | 0.259 (0.178,0.355) |
| CXR-CAD | CRP --> LAM | |||||||||
| Pooled PHC | 0.113 (0.105,0.121) | 0.5984 (0.5854,0.6113) | 0.791 (0.758,0.823) | 0.985 (0.981,0.988) | 0.867 (0.838,0.893) | 0.974 (0.969,0.978) | 0.103 (0.096,0.111) | 51.039 (41.086,64.737) | 0.212 (0.180,0.246) |
| Cameroon PHC | 0.079 (0.063,0.097) | 0.617 (0.5861,0.6472) | 0.785 (0.686,0.865) | 0.975 (0.964,0.984) | 0.730 (0.630,0.817) | 0.981 (0.971,0.989) | 0.085 (0.069,0.103) | 31.253 (21.269,48.799) | 0.221 (0.138,0.323) |
| Nigeria ZRC PHC | 0.219 (0.191,0.248) | 0.5271 (0.4894,0.5647) | 0.811 (0.745,0.868) | 0.985 (0.973,0.993) | 0.939 (0.890,0.971) | 0.949 (0.929,0.965) | 0.189 (0.162,0.218) | 55.759 (29.606,119.590) | 0.192 (0.134,0.259) |
| Kenya PHC | 0.084 (0.066,0.106) | 0.6086 (0.5713,0.6449) | 0.779 (0.661,0.871) | 0.978 (0.965,0.988) | 0.768 (0.649,0.861) | 0.980 (0.967,0.989) | 0.086 (0.066,0.108) | 35.568 (21.716,63.877) | 0.226 (0.132,0.348) |
| Bangladesh PHC | 0.034 (0.024,0.046) | 0.65 (0.6195,0.6796) | 0.823 (0.678,0.926) | 0.992 (0.984,0.996) | 0.778 (0.627,0.893) | 0.994 (0.987,0.998) | 0.036 (0.026,0.049) | 99.271 (51.646,216.489) | 0.178 (0.075,0.325) |
| Brazil Aracaju PHC | 0.148 (0.120,0.180) | 0.568 (0.5233,0.6119) | 0.824 (0.732,0.900) | 0.991 (0.979,0.997) | 0.938 (0.863,0.980) | 0.970 (0.951,0.983) | 0.130 (0.103,0.161) | 86.250 (38.568,274.792) | 0.178 (0.101,0.271) |
| Brazil Maceio PHC | 0.282 (0.246,0.320) | 0.494 (0.4493,0.5387) | 0.751 (0.675,0.816) | 0.981 (0.963,0.992) | 0.938 (0.883,0.973) | 0.910 (0.879,0.936) | 0.225 (0.191,0.263) | 38.637 (20.309,90.775) | 0.254 (0.188,0.331) |
| Malawi PHC | 0.078 (0.064,0.093) | 0.6317 (0.6037,0.659) | 0.795 (0.705,0.868) | 0.988 (0.981,0.994) | 0.850 (0.765,0.914) | 0.983 (0.974,0.990) | 0.072 (0.059,0.088) | 67.716 (41.095,122.542) | 0.207 (0.133,0.298) |
In figure Figure 1 we show how we plan to summarise sensitivities and specificities (the primary interest of the performance evaluation).
Code
algoNames<-c("Poolxpert.Xpert",
"Xpert",
"Lam",
"Cxr.Poolxpert.Xpert",
"Crp.Poolxpert.Xpert",
"Lam.Poolxpert.Xpert",
"CxrCrpLam.Poolxpert.Xpert",
"CxrLam.Poolxpert.Xpert",
"CrpLam.Poolxpert.Xpert",
"CxrCrp.Poolxpert.Xpert",
"Cxr.Xpert",
"Crp.Xpert",
"Lam.Xpert",
"CxrCrpLam.Xpert",
"CxrLam.Xpert",
"CrpLam.Xpert",
"CxrCrp.Xpert",
"Cxr.Lam",
"Crp.Lam",
"CxrCrp.Lam"
)
algoLabels<-c("Pooled Xpert Ultra --> Xpert Ultra",
"Xpert Ultra",
"LAM",
"CXR-CAD --> Pooled Xpert Ultra --> Xpert Ultra",
"CRP --> Pooled Xpert Ultra --> Xpert Ultra",
"Lam --> Poolxpert --> Xpert",
"CXR-CAD | CRP | LAM --> Pooled Xpert Ultra --> Xpert Ultra",
"CXR-CAD | LAM --> Pooled Xpert Ultra --> Xpert Ultra",
"CRP | LAM --> Pooled Xpert Ultra --> Xpert Ultra",
"CXR-CAD | CRP --> Pooled Xpert Ultra --> Xpert Ultra",
"CXR-CAD --> Xpert Ultra",
"CRP --> Xpert Ultra",
"LAM --> Xpert Ultra",
"CXR-CAD | CRP | LAM --> Xpert Ultra",
"CXR-CAD | LAM --> Xpert Ultra",
"CRP | LAM --> Xpert Ultra",
"CXR-CAD | CRP --> Xpert Ultra",
"CXR-CAD --> LAM",
"CRP --> LAM",
"CXR-CAD | CRP --> LAM"
)
settings<-paste(sep="_",dfResPrimBayes$country,dfResPrimBayes$region,dfResPrimBayes$setting)
settings<-settings[grepl(pattern="PHC",settings)]
settings<-settings[c(length(settings),1:(length(settings)-1))]
gr<-expand.grid(settings,algoNames)
dfAlgos<-data.frame(
setting=gr[,1],
algo=gr[,2],
label=algoLabels[match(gr[,2],algoNames)],
sensTxt=NA,
sensMedian=NA,
sensLow=NA,
sensUpp=NA,
specTxt=NA,
specMedian=NA,
specLow=NA,
specUpp=NA,
ppvTxt=NA,
ppvMedian=NA,
ppvLow=NA,
ppvUpp=NA,
npvTxt=NA,
npvMedian=NA,
npvLow=NA,
npvUpp=NA,
dytTxt=NA,
dytMedian=NA,
dytLow=NA,
dytUpp=NA,
dydTxt=NA,
dydMedian=NA,
dydLow=NA,
dydUpp=NA,
lrpTxt=NA,
lrpMedian=NA,
lrpLow=NA,
lrpUpp=NA,
lrmTxt=NA,
lrmMedian=NA,
lrmLow=NA,
lrmUpp=NA
)
for(j in 1:nrow(dfAlgos)){
res<-allRes[[as.character(dfAlgos$setting[j])]]
par<-dfAlgos$algo[j]
# sensitivity
pointEstimate<-gsub(pattern=" ",replacement="",res$mcmcSummary[paste(sep="","pse.",par),"50%"])
ci<-paste(sep="","(",gsub(pattern=" ",replacement="",paste(collapse=",",res$mcmcSummary[paste(sep="","pse.",par),c("2.5%","97.5%")])),")")
dfAlgos$sensTxt[j]<-paste(sep=" ",pointEstimate,ci)
dfAlgos$sensMedian[j]<-pointEstimate
dfAlgos$sensLow[j]<-res$mcmcSummary[paste(sep="","pse.",par),c("2.5%")]
dfAlgos$sensUpp[j]<-res$mcmcSummary[paste(sep="","pse.",par),c("97.5%")]
# specificity
pointEstimate<-gsub(pattern=" ",replacement="",res$mcmcSummary[paste(sep="","psp.",par),"50%"])
ci<-paste(sep="","(",gsub(pattern=" ",replacement="",paste(collapse=",",res$mcmcSummary[paste(sep="","psp.",par),c("2.5%","97.5%")])),")")
dfAlgos$specTxt[j]<-paste(sep=" ",pointEstimate,ci)
dfAlgos$specMedian[j]<-pointEstimate
dfAlgos$specLow[j]<-res$mcmcSummary[paste(sep="","psp.",par),c("2.5%")]
dfAlgos$specUpp[j]<-res$mcmcSummary[paste(sep="","psp.",par),c("97.5%")]
# PPV
pointEstimate<-gsub(pattern=" ",replacement="",res$mcmcSummary[paste(sep="","ppv.",par),"50%"])
ci<-paste(sep="","(",gsub(pattern=" ",replacement="",paste(collapse=",",res$mcmcSummary[paste(sep="","ppv.",par),c("2.5%","97.5%")])),")")
dfAlgos$ppvTxt[j]<-paste(sep=" ",pointEstimate,ci)
dfAlgos$ppvMedian[j]<-pointEstimate
dfAlgos$ppvLow[j]<-res$mcmcSummary[paste(sep="","ppv.",par),c("2.5%")]
dfAlgos$ppvUpp[j]<-res$mcmcSummary[paste(sep="","ppv.",par),c("97.5%")]
# NPV
pointEstimate<-gsub(pattern=" ",replacement="",res$mcmcSummary[paste(sep="","npv.",par),"50%"])
ci<-paste(sep="","(",gsub(pattern=" ",replacement="",paste(collapse=",",res$mcmcSummary[paste(sep="","npv.",par),c("2.5%","97.5%")])),")")
dfAlgos$npvTxt[j]<-paste(sep=" ",pointEstimate,ci)
dfAlgos$npvMedian[j]<-pointEstimate
dfAlgos$npvLow[j]<-res$mcmcSummary[paste(sep="","npv.",par),c("2.5%")]
dfAlgos$npvUpp[j]<-res$mcmcSummary[paste(sep="","npv.",par),c("97.5%")]
# DYT
pointEstimate<-gsub(pattern=" ",replacement="",res$mcmcSummary[paste(sep="","dyt.",par),"50%"])
ci<-paste(sep="","(",gsub(pattern=" ",replacement="",paste(collapse=",",res$mcmcSummary[paste(sep="","dyt.",par),c("2.5%","97.5%")])),")")
dfAlgos$dytTxt[j]<-paste(sep=" ",pointEstimate,ci)
dfAlgos$dytMedian[j]<-pointEstimate
dfAlgos$dytLow[j]<-res$mcmcSummary[paste(sep="","dyt.",par),c("2.5%")]
dfAlgos$dytUpp[j]<-res$mcmcSummary[paste(sep="","dyt.",par),c("97.5%")]
# LR+
pointEstimate<-gsub(pattern=" ",replacement="",res$mcmcSummary[paste(sep="","lrp.",par),"50%"])
ci<-paste(sep="","(",gsub(pattern=" ",replacement="",paste(collapse=",",res$mcmcSummary[paste(sep="","lrp.",par),c("2.5%","97.5%")])),")")
dfAlgos$lrpTxt[j]<-paste(sep=" ",pointEstimate,ci)
dfAlgos$lrpMedian[j]<-pointEstimate
dfAlgos$lrpLow[j]<-res$mcmcSummary[paste(sep="","lrp.",par),c("2.5%")]
dfAlgos$lrpUpp[j]<-res$mcmcSummary[paste(sep="","lrp.",par),c("97.5%")]
# LR-
pointEstimate<-gsub(pattern=" ",replacement="",res$mcmcSummary[paste(sep="","lrm.",par),"50%"])
ci<-paste(sep="","(",gsub(pattern=" ",replacement="",paste(collapse=",",res$mcmcSummary[paste(sep="","lrm.",par),c("2.5%","97.5%")])),")")
dfAlgos$lrmTxt[j]<-paste(sep=" ",pointEstimate,ci)
dfAlgos$lrmMedian[j]<-pointEstimate
dfAlgos$lrmLow[j]<-res$mcmcSummary[paste(sep="","lrm.",par),c("2.5%")]
dfAlgos$lrmUpp[j]<-res$mcmcSummary[paste(sep="","lrm.",par),c("97.5%")]
}
uniqueAlgos<-unique(dfAlgos$label)
for(i in 1:length(uniqueAlgos)){
if(i==1){
dt<-c(uniqueAlgos[i],rep("",10))
names(dt)<-c("Setting","sensCI","sensEst","sensLow","sensHigh","Sensitivity","specCI","specEst","specLow","specHigh","Specificity")
}else{
dt<-rbind(dt,c(uniqueAlgos[i],rep("",10)))
}
dfAlgosTmp<-dfAlgos %>% dplyr::filter(label==uniqueAlgos[i])
dtTmp<-cbind(gsub(paste(sep=""," ",dfAlgosTmp$setting),pattern="_+",replacement=" "),
dfAlgosTmp$sensTxt,dfAlgosTmp$sensMedian,dfAlgosTmp$sensLow,dfAlgosTmp$sensUpp,paste(rep(" ", 20), collapse = " "),
dfAlgosTmp$specTxt,dfAlgosTmp$specMedian,dfAlgosTmp$specLow,dfAlgosTmp$specUpp,paste(rep(" ", 20), collapse = " "))
colnames(dtTmp)<-c("Setting","sensCI","sensEst","sensLow","sensHigh","Sensitivity","specCI","specEst","specLow","specHigh","Specificity")
dt<-rbind(dt,dtTmp)
rm(dtTmp,dfAlgosTmp)
}
dt<-as.data.frame(dt)
dt$sensEst<-as.double(dt$sensEst)
dt$sensLow<-as.double(dt$sensLow)
dt$sensHigh<-as.double(dt$sensHigh)
dt$specEst<-as.double(dt$specEst)
dt$specLow<-as.double(dt$specLow)
dt$specHigh<-as.double(dt$specHigh)
dt$sensCI[dt$sensCI=="NA"]<-""
dt$specCI[dt$specCI=="NA"]<-""
# Set-up theme
tm <- forest_theme(base_size = 10,
refline_gp = gpar(lty="blank"),
ci_pch = c(15),
ci_col = c("steelblue"),
footnote_gp = gpar(col = "darkgreen",fontsize=8),
vertline_lty = c("dashed", "dashed"),
vertline_col = c("darkred","orange"),
# Table cell padding, width 4 and heights 3
core = list(padding = unit(c(4, 3), "mm")))
p <- forest(dt[,c("Setting","sensCI","Sensitivity","specCI","Specificity")],
est = list(dt$sensEst,dt$specEst),
lower = list(dt$sensLow,dt$specLow),
upper = list(dt$sensHigh,dt$specHigh),
ci_column = c(3, 5),
ref_line = 1,
vert_line = list(c(0.75,0.85),c(0.90,0.95)),
nudge_y = 0,
theme = tm,
xlim=c(0,1),
footnote="The dashed lines indicate minimum (red) and optimum (orange) thresholds.")
plot(p)
pdf(paste(sep="",outPrefix,"S4A_mcmcPars_forestPlot_PcfIcfPHC_",gsub(pattern="-",replacement="",Sys.Date()),".pdf"),width=11,height=40)
plot(p)
dev.off()quartz_off_screen
2
5.5.1.3 PCF / ICF district level
The PCF/ICF district-level results (which will be for the exact same algorithms) will be presented in the same way as the results for the lowest level of care setting (but obviously slight variation in countries for which data are available).
5.5.1.4 ACF W4SS entry
The ACF W4SS district-level results (which will be for the exact same algorithms) will be presented in the same way as the results for the lowest level of care setting (but obviously slight variation in countries for which data are available as well as multiple settings that use ACF).
5.5.1.5 ACF CXR-CAD entry
These will be presented similarly, though involve a different set of evaluated algorithms (see Section 5.2.4).
5.5.1.6 ACF (W4SS or CXR-CAD) entry
These will be presented similarly, though involve a different set of evaluated algorithms (see Section 5.2.4).
5.6 Link-up with the health economic analysis
5.6.1 Beta distributions for parameters
All (except for the likelihood ratios) of the performance metrics and parameters associated with intermediate steps in the different algorithms that we estimate are probability parameters and they will directly inform the decision tree model used in the planned health economic analysis. To allow propagating the uncertainty of each of the above estimates, we will need to input the entire posterior distribution for each parameter into the health economic modelling.
The easiest way, for each parameter, to do this is to use quantile matching to identify the best fitting beta distribution for each empirical distribution. We will then use the estimated beta distribution parameters to feed into the health economic modelling.
6 List of figures
Figure 1: PCF/ICF evaluation (all participants): forest plots showing the Bayesian posterior estimates for sensitivity and specificity for PHC / lowest level of primary care settings.
The final version of the SAP will include figures for other settings beyond PCF/ICF.
7 List of tables
Table 1: List of abbreviations
Table 2: Version history of the SAP since v1.0.
Table 3: Summary of study populations, countries, and procedures.
Table 4: Summary of diagnostic assays evaluated in this study.
Table 5: Sample size calculation for adults.
Table 6: Sample size for each survey.
Table 7: 10 random rows from the simulated data.
Table 8: Summary of the study data.
Table 9: Summary of the performance of individual tests compared against culture and Xpert Ultra.
Table 10: PCF/ICF evaluation (all participants): Bayesian posterior estimates for sensitivity, specificity, positive and negative predictive values and positive and negative likelihood ratios for PHC / lowest level of primary care settings.
The final version of the SAP will include mock-ups tables for other settings beyond PCF/ICF.